Compare commits
70 Commits
1b338e4c19
...
developmen
Author | SHA1 | Date | |
---|---|---|---|
aaaf902759 | |||
c6f382bb0f | |||
ea58248be2 | |||
e89b4f39b2 | |||
59a79519c0 | |||
9581791fd6 | |||
48adbd7021 | |||
fcb2c39e4d | |||
b391bcbb9f | |||
1b004bee2d | |||
594e77fc77 | |||
89970dc4e2 | |||
190e4b4a98 | |||
8d6d1d258d | |||
b32d7f302e | |||
089480620e | |||
bc9d6b74fd | |||
525da2fbe0 | |||
ecc16e6cbf | |||
e1f8ba0c2b | |||
037fbabeae | |||
6732315b96 | |||
3131258491 | |||
6ff4779cfb | |||
1c83547aaa | |||
40f8e4d8b1 | |||
7b009f7378 | |||
de3934a761 | |||
1b7d108a29 | |||
ca7a9baab8 | |||
274c32c673 | |||
e806a5652e | |||
703b6a67b2 | |||
0159fd6ed8 | |||
2b8513abf0 | |||
146dd508d6 | |||
20f5c3b5d7 | |||
d340fb3375 | |||
bc3f1e8a68 | |||
44adc6c8ab | |||
6cb66db46f | |||
a08ea057cc | |||
30605d7998 | |||
121be79e03 | |||
c4ca06fba4 | |||
9271702a62 | |||
861bef0ce1 | |||
3b86ab0e88 | |||
9f62e2a458 | |||
bd393e3dd4 | |||
9c73885f1b | |||
dbac9326b3 | |||
dd0a6a01b9 | |||
c294f9c8f5 | |||
71a510170d | |||
d577b12a33 | |||
fb090b6f63 | |||
75cda05579 | |||
97e63f1daa | |||
dce169109c | |||
4c6473a7b0 | |||
204a20b793 | |||
bf1a60439f | |||
006d7ab0c2 | |||
cca693d02d | |||
bb88a7025d | |||
8da10a147b | |||
653e29ffe5 | |||
b13610ef0e | |||
8739eba655 |
2
.cz.yaml
2
.cz.yaml
@ -17,5 +17,5 @@ commitizen:
|
||||
prerelease_offset: 1
|
||||
tag_format: $version
|
||||
update_changelog_on_bump: false
|
||||
version: 1.18.0
|
||||
version: 1.19.0
|
||||
version_scheme: semver
|
||||
|
13
.github/workflows/ci.yaml
vendored
13
.github/workflows/ci.yaml
vendored
@ -46,6 +46,19 @@ jobs:
|
||||
WORKFLOW_TOKEN: ${{ secrets.WORKFLOW_TOKEN }}
|
||||
|
||||
|
||||
integration-test:
|
||||
name: 'Integration Test'
|
||||
uses: nofusscomputing/action_python/.github/workflows/python-integration.yaml@development
|
||||
needs:
|
||||
- docker
|
||||
with:
|
||||
POSTGRES_VERSIONS: '[ "13", "14", "15", "16", "17" ]'
|
||||
PYTHON_VERSION: '3.11'
|
||||
RABBITMQ_VERSIONS: '[ "3.12", "3.13", "4.0", "4.1" ]'
|
||||
secrets:
|
||||
WORKFLOW_TOKEN: ${{ secrets.WORKFLOW_TOKEN }}
|
||||
|
||||
|
||||
gitlab-mirror:
|
||||
if: ${{ github.repository == 'nofusscomputing/centurion_erp' }}
|
||||
runs-on: ubuntu-latest
|
||||
|
5
.gitignore
vendored
5
.gitignore
vendored
@ -21,3 +21,8 @@ feature_flags.json
|
||||
coverage_*.json
|
||||
*-coverage.xml
|
||||
log/
|
||||
# Integration testing
|
||||
app/artifacts/
|
||||
app/pyproject.toml
|
||||
app/histogram_**
|
||||
app/counter_**
|
||||
|
695
CHANGELOG.md
695
CHANGELOG.md
@ -1,3 +1,698 @@
|
||||
## 1.19.0 (2025-08-15)
|
||||
|
||||
### feat
|
||||
|
||||
- **core**: add to migration signal system user and use for inventory objects
|
||||
- **docker**: Adjust gunicorn works=4 100reqs/max and preload app
|
||||
- **api**: Ensure that serializer converts Django exceptions to rest_framework exceptions
|
||||
- **access**: Filter history permissions
|
||||
- **access**: Add Audit and notes tables for model Role
|
||||
- **access**: Add AuditHistory Serializer for Role model
|
||||
- **access**: Add Notes Serializer for Role model
|
||||
- **itam**: Add AuditHistory Serializer for ITAMAssetBase model
|
||||
- **itam**: Add Notes Serializer for ITAMAssetBase model
|
||||
- **accounting**: Add AuditHistory Serializer for AssetBase model
|
||||
- **accounting**: Add Notes Serializer for AssetBase model
|
||||
- When attempting to create and objetc must be unique and alrready exists, dont return error return existing object
|
||||
- **access**: History + Notes model migrations for Company Model
|
||||
- **api**: map notfound and perm denied django -> drf exceptions
|
||||
- **human_resources**: Add model tag for Employee model
|
||||
- **human_resources**: Add AuditHistory Serializer for Employee model
|
||||
- **human_resources**: Add Notes Serializer for Employee model
|
||||
- **human_resources**: Change model to inherit from `CenturionModel` for Employee model
|
||||
- **access**: Add model tag for Person model
|
||||
- **access**: Add AuditHistory Serializer for Person model
|
||||
- **access**: Add Notes Serializer for Person model
|
||||
- **access**: Change model to inherit from `CenturionModel` for Person model
|
||||
- **access**: Add model tag for Contact model
|
||||
- **access**: Add AuditHistory Serializer for Contact model
|
||||
- **access**: Add Notes Serializer for Contact model
|
||||
- **access**: Change model to inherit from `CenturionModel` for Contact model
|
||||
- **access**: Add AuditHistory Serializer for Company model
|
||||
- **access**: Add Notes Serializer for Entity model
|
||||
- **access**: Change model to inherit from `CenturionModel` for Company model
|
||||
- **access**: Change model to inherit from `CenturionModel` for Entity model
|
||||
- **access**: Add AuditHistory Serializer for Entity model
|
||||
- **access**: Add Notes Serializer for Entity model
|
||||
- **access**: Change model to inherit from `CenturionModel` for Entity model
|
||||
- **settings**: Add model tag for ExtrnalLink model
|
||||
- **settings**: Add AuditHistory Serializer for UserSettings model
|
||||
- **settings**: Add Notes Serializer for UserSettings model
|
||||
- **settings**: Change model to inherit from `CenturionModel` for UserSettings model
|
||||
- **settings**: Add model ExternalLink to migrate for history and notes
|
||||
- **settings**: Add AuditHistory Serializer for ExternalLink model
|
||||
- **settings**: Add Notes Serializer for ExternalLink model
|
||||
- **settings**: Change model to inherit from `CenturionModel` for ExternalSettings model
|
||||
- **settings**: Add model AppSettings to migrate for history and notes
|
||||
- **settings**: Add AuditHistory Serializer for AppSettings model
|
||||
- **settings**: Add Notes Serializer for AppSettings model
|
||||
- **settings**: Change model to inherit from `CenturionModel` for AppSettings model
|
||||
- **project_management**: Add model ProjectType to migrate for history and notes
|
||||
- **project_management**: Add AuditHistory Serializer for ProjectTYpe model
|
||||
- **project_management**: Add Notes Serializer for ProjectType model
|
||||
- **project_management**: Change model to inherit from `CenturionModel` for ProjectType model
|
||||
- **project_management**: Add model ProjectState to migrate for history and notes
|
||||
- **project_management**: Add AuditHistory Serializer for ProjectState model
|
||||
- **project_management**: Add Notes Serializer for ProjectState model
|
||||
- **project_management**: Change model to inherit from `CenturionModel` for ProjectState model
|
||||
- **project_management**: Add model ProjectMilestone to migrate for history and notes
|
||||
- **project_management**: Add AuditHistory Serializer for ProjectMilestone model
|
||||
- **project_management**: Add Notes Serializer for ProjectMilestone model
|
||||
- **project_management**: Change model to inherit from `CenturionModel` for ProjectManagement model
|
||||
- **project_management**: Add model Project to migrate for history and notes
|
||||
- **project_management**: Add AuditHistory Serializer for Project model
|
||||
- **project_management**: Add Notes Serializer for Project model
|
||||
- **project_management**: Change model to inherit from `CenturionModel` for Project model
|
||||
- **itim**: Add model Service to migrate for history and notes
|
||||
- **itim**: Add AuditHistory Serializer for Service model
|
||||
- **itim**: Add Notes Serializer for Service model
|
||||
- **itim**: Change model to inherit from `CenturionModel` for Service model
|
||||
- **itim**: Add model Port to migrate for history and notes
|
||||
- **itim**: Add AuditHistory Serializer for Port model
|
||||
- **itim**: Add Notes Serializer for Port model
|
||||
- **itim**: Change model to inherit from `CenturionModel` for Port model
|
||||
- **itim**: Add AuditHistory Serializer for ClusterType model
|
||||
- **itim**: Add Notes Serializer for ClusterType model
|
||||
- **itim**: Change model to inherit from `CenturionModel` for ClusterType model
|
||||
- **itim**: Add model Cluster to migrate for history and notes
|
||||
- **itim**: Add Notes Serializer for Cluster model
|
||||
- **itim**: Add AuditHistory Serializer for Cluster model
|
||||
- **itim**: Change model to inherit from `CenturionModel` for Cluster model
|
||||
- **itam**: Add model SoftwareVersion to migrate for history and notes
|
||||
- **itam**: Add Notes Serializer for SoftwareVersiony model
|
||||
- **itam**: Add AuditHistory Serializer for SoftwareVersion model
|
||||
- **itam**: Change model to inherit from `CenturionModel` for SoftwareVersion model
|
||||
- **itam**: Add model SoftwareCategory to migrate for history and notes
|
||||
- **itam**: Add Notes Serializer for SoftwareCategory model
|
||||
- **itam**: Add AuditHistory Serializer for SoftwareCategory model
|
||||
- **itam**: Change model to inherit from `CenturionModel` for SoftwareCategory model
|
||||
- **itam**: Add model Software to migrate for history and notes
|
||||
- **itam**: Add Notes Serializer for Software model
|
||||
- **itam**: Add AuditHistory Serializer for Software model
|
||||
- **itam**: Change model to inherit from `CenturionModel` for Software model
|
||||
- **itam**: Add model OperatingSystemVersion to migrate for history and notes
|
||||
- **itam**: Add Notes Serializer for OperatingSystemVersion model
|
||||
- **itam**: Add AuditHistory Serializer for OperatingSystemVersion model
|
||||
- **itam**: Change model to inherit from `CenturionModel` for OperatingSystemVersion model
|
||||
- **itam**: Add model OperatingSystem to migrate for history and notes
|
||||
- **itam**: Add Note Serializer for DeviceSoftware model
|
||||
- **itam**: Add AuditHistory Serializer for DeviceSoftware model
|
||||
- **itam**: Change model to inherit from `CenturionModel` for DeviceSoftware model
|
||||
- **itam**: Change model to inherit from `Centurion` for DeviceSoftware model
|
||||
- **itam**: Add model_tag to DeviceType model
|
||||
- **itam**: Add DeviceType for history and notes data migration
|
||||
- **itam**: Add DeviceModel for history and notes data migration
|
||||
- **itam**: Add DEvice for history and notes data migration
|
||||
- **devops**: Switch SoftwareEnabledFeatureFlag model to inherit from CenturionModel
|
||||
- **devops**: Update checkin model fixture so it creates the feature flag
|
||||
- **devops**: Add methods get_url and get_url_kwargs to CheckIn model
|
||||
- **devops**: Add migration to signal
|
||||
- **devops**: Add migration to signal
|
||||
- **devops**: Add migration to signal
|
||||
- **devops**: Add migration to signal
|
||||
- **devops**: Update URL route basename
|
||||
- **devops**: Migrations for switching GitLabRepository model to inherit from `CenturionModel`
|
||||
- **devops**: Migrations for switching GitRepository model to inherit from `CenturionModel`
|
||||
- **devops**: Migrations for switching GitRepository model to inherit from `CenturionModel`
|
||||
- **devops**: Serializers for GitRepository models notes and history
|
||||
- **devops**: Serializers for GitHubGitRepository models notes and history
|
||||
- **devops**: Serializers for GitLabGitRepository models notes and history
|
||||
- **devops**: Switch GitLabGitRepository model to inherit from `CenturionModel`
|
||||
- **devops**: Switch GitHubGitRepository model to inherit from `CenturionModel`
|
||||
- **devops**: Switch GitRepository model to inherit from `CenturionModel`
|
||||
- **devops**: Update Checkin model url route basename
|
||||
- **devops**: Add app_namespace Checkin model
|
||||
- **devops**: Add Checkin to migrate model history/notes
|
||||
- **devops**: Migrations for switching Checkin model to inherit from `CenturionModel`
|
||||
- **devops**: Switch Checkin model to inherit from `CenturionModel`
|
||||
- **core**: add TicketCommentCategory to history/notes migration
|
||||
- **core**: add model tag to ticket comment category
|
||||
- **core**: Migrations for TicketCategory
|
||||
- **core**: add TicketCategory to history/notes migration
|
||||
- **core**: add model tag to ticket category
|
||||
- **core**: add Manufacturer to history/notes migration
|
||||
- **core**: add model tag to manufacturer
|
||||
- **config_management**: add ConfigGroups to history/notes migration
|
||||
- **config_management**: add ConfigGroupSoftware to history/notes migration
|
||||
- **config_management**: add ConfigGroupHosts to history/notes migration
|
||||
- **access**: add tenant to history/notes migration
|
||||
- **access**: Migration for switching model inheritence to `CenturionModel`
|
||||
- **itam**: Update model methods
|
||||
- **access**: Migration for switching model inheritence to `CenturionMixin`
|
||||
- **access**: Switch model inheritence to `CenturionMixin`
|
||||
- **itam**: Update url basename
|
||||
- **itam**: Update url basename
|
||||
- **base**: add support for manytomany for model unit tests
|
||||
- **itam**: Update url basename
|
||||
- **core**: Update url basename
|
||||
- **core**: Update url basename
|
||||
- **core**: Update url basename
|
||||
- **core**: Update url basename
|
||||
- **core**: Update url basename
|
||||
- **core**: Update url basename
|
||||
- **access**: TeamUsers do not require notes
|
||||
- **config_management**: ConfigGroupHosts and ConfigGroupSoftware do not require notes
|
||||
- **config_management**: Add url_kwargs to ConfigGroupSoftware model
|
||||
- **access**: Add url_kwargs to Team model
|
||||
- **access**: Add url_kwargs to TeamUser model
|
||||
- **access**: Update TeamUser API basename
|
||||
- **access**: Update Team API basename
|
||||
- **itam**: switch model Device to inheirt from CenturionModel
|
||||
- **itam**: switch model DeviceType to inheirt from CenturionModel
|
||||
- **itam**: switch model DeviceModel to inheirt from CenturionModel
|
||||
- **core**: switch model TicketCategory to inheirt from CenturionModel
|
||||
- **core**: switch model TicktetCommentCategory to inheirt from CenturionModel
|
||||
- **core**: switch model Manufacturer to inheirt from CenturionModel
|
||||
- **config_management**: switch model ConfigGroupHosts to inheirt from CenturionModel
|
||||
- **config_management**: switch model ConfigGroupSoftware to inheirt from CenturionModel
|
||||
- **config_management**: switch model ConfigGroups to inheirt from CenturionModel
|
||||
- **access**: switch model TeamUsers to inheirt from CenturionModel
|
||||
- **access**: switch model Team to inheirt from CenturionModel
|
||||
- **core**: If user context not supplied, dont create audithistory for model
|
||||
- **access**: Add init to tenancy model to clear state
|
||||
- **core**: Ensure that model has user context
|
||||
- **core**: Add supprt to model_instance fixture for manytomany field
|
||||
- **core**: Add supprt to model create test for manytomany field
|
||||
- **assistance**: migrations for new history and notes models for KnowledgeBaseCategory model
|
||||
- **assistance**: migrations for new history and notes models for KnowledgeBase model
|
||||
- **assistance**: Model inheritance migrations
|
||||
- **core**: Migrate Centurion Model history and notes within a post_migrate signal
|
||||
- **core**: Add ability to CenturionModel `get_url` to be either detail/list
|
||||
- **core**: New Management command to list models
|
||||
- **devops**: Switch model FeatureFlag inheritance to CenturionModel
|
||||
- **core**: Disable Notes for model CenturionModelNote
|
||||
- **devops**: Enable Model notes for GitGroup
|
||||
- **core**: add Swagger docs for CenturionModelNotes ViewSet
|
||||
- **core**: Meta Model for CenturionModelNotes
|
||||
- **core**: Finalize Serializer for CenturionModelNotes
|
||||
- **api**: Add to common serializer meta notes model for notes url
|
||||
- **core**: Interim Meta model CenturionNotes
|
||||
- **core**: Interim ViewSet for model CenturionNotes
|
||||
- **core**: URL Route for model CenturionNotes
|
||||
- **core**: Serializer for model CenturionNotes
|
||||
- **core**: Migration for model CenturionNotes
|
||||
- **core**: Add model CenturionNotes
|
||||
- **devops**: dont allow deleting a git group if it has children
|
||||
- **devops**: Add model tag attribute to model
|
||||
- **core**: Add to Centurion Model an attribute to set the models tag
|
||||
- **core**: Add Context to model when ViewSet loads
|
||||
- **devops**: Add AuditHistory Serializer for GitGroup
|
||||
- **core**: Add AuditHistory Serializer
|
||||
- **core**: Add AuditHistory ViewSet
|
||||
- **core**: Add URL route for AuditHistory
|
||||
- **core**: Add audithistory URL to serializer for models with `_audit_enabled=True`
|
||||
- **core**: Models url kwarg helper
|
||||
- **core**: Support setting custom model name for url basename
|
||||
- **api**: Add sub-model filter to `get_queryset` method
|
||||
- **core**: Disable models audit history on model delete
|
||||
- **core**: Use Previous TenancyManager until UserModel rewrite done
|
||||
- **core**: Process a models history within AuditHistory
|
||||
- **core**: Enable AuditHistory signal to start when apps are ready
|
||||
- **core**: Add model instance to history object during history creation
|
||||
- **core**: Update Meta AuditModel `db_name` to be suffixed `_audithistory`
|
||||
- **core**: remove unnessecary method `clean_fields` from audit model
|
||||
- **core**: remove un-needed field `model_notes` from audit models
|
||||
- **core**: Run meta models create on Core module ready
|
||||
- **core**: New model core.CenturionAudit
|
||||
- **core**: cause sub-audit models to chuck a wobbler if clean_fields not re-implementated
|
||||
- **access**: remove mill-seconds from datetime auto fields
|
||||
- **core**: Centurion model Base
|
||||
- **core**: Centurion Audit model
|
||||
- **core**: permissions getter for role model
|
||||
- **core**: Audit History Signal for Delete/Save
|
||||
- **core**: Dynamic History model creation
|
||||
|
||||
### Fixes
|
||||
|
||||
- remove trailing slant from URLs
|
||||
- **access**: When creating permission QuerySet prevent app crash if db not setup
|
||||
- **itim**: Ensure during testing, fixture vals are copied for Model Service
|
||||
- **base**: on fixture cleanup, only clean if obj exists
|
||||
- **core**: required field must be null for logical chek to function
|
||||
- **itam**: field slug no longer avail, use str
|
||||
- **core**: Include model so content type is created
|
||||
- **settings**: AppSettings requires super user perms
|
||||
- **api**: Convert Django Exceptions to DRF API Exception equivilent
|
||||
- **api**: Ensure if exception DRF, message returned is from that exception
|
||||
- **devops**: git repository is sub-model ViewSet must inherit from SubModel
|
||||
- **access**: entity field `entity_type` is an auto field
|
||||
- **access**: Ensure that if method not allowed, exception is thrown first before perms check
|
||||
- **itam**: Model software must be related linked to organization model
|
||||
- **access**: if user has no orgs, dont filter by for query
|
||||
- **devops**: Ensure mandatory fields are writeable for model GitRepository
|
||||
- **access**: add property organization to Tenant model
|
||||
- **itam**: Add missing import `now`
|
||||
- **core**: notes meta model must add `model_kwargs` fixture
|
||||
- **core**: clean_fields for created_by field belongs in model that contains field
|
||||
- **core**: audit meta model must add `model_kwargs` fixture
|
||||
- model fixture names must match model_name
|
||||
- clean up mock model from django apps
|
||||
- **core**: When obtaining model fields ensure it exists first
|
||||
- **access**: use getattr instead as attribute may exist as None
|
||||
- **assistance**: make kb article field longer for model name
|
||||
- **assistance**: Add missing field `model_notes` to KB serializer
|
||||
- **core**: Before attempting to get model audit data confirm fields dont already exist
|
||||
- **api**: check if model has notes enabled before adding url to body
|
||||
- **api**: Only return View Serialized data if status code is HTTP/2xx
|
||||
- **core**: Conduct kwargs check fr ticket comment serializer during init
|
||||
- **core**: Enable CenturionAudit model to get model history for item being deleted
|
||||
- **core**: When creating the AuditHistory entry for a model, use the user from context
|
||||
- **core**: When collecting AuditHistory cater for models being created
|
||||
- **api**: remove surerflous feature for fetching app_namespace for models metadata
|
||||
- **core**: Correct attribute names for referencing a Centurion Model from an AuditModel
|
||||
- **core**: Correct before lookup for current models audit history
|
||||
- **core**: When deleting a model check if sub-model within delete method
|
||||
- **access**: Tenancy Manager should not attempt to get org as related field if it does not exist
|
||||
- **api**: ensure val returns at least none
|
||||
|
||||
### Refactoring
|
||||
|
||||
- **docker**: update healthcheck interval=10s and start-period=30s
|
||||
- **docker**: when l;aunching gunicorn create a pid file
|
||||
- **devops**: API Fields render Functional Test Suite re-written to Pytest for model SoftwareEnableFeatureFlag Again
|
||||
- **devops**: Remove old test suites no longer required model SoftwareEnableFeatureFlag
|
||||
- **devops**: ViewSet Unit Test Suite re-written to Pytest for model SoftwareEnableFeatureFlag
|
||||
- **devops**: Serializer Unit Test Suite re-written to Pytest for model SoftwareEnableFeatureFlag
|
||||
- **devops**: API Fields render Functional Test Suite re-written to Pytest for model SoftwareEnableFeatureFlag
|
||||
- **devops**: Model Functional Test Suite re-written to Pytest for model SoftwareEnableFeatureFlag
|
||||
- **devops**: API Metadata Functional Test Suite re-written to Pytest for model SoftwareEnableFeatureFlag
|
||||
- **devops**: Remove old test suites no longer required model FeatureFlag
|
||||
- **devops**: ViewSet Unit Test Suite re-written to Pytest for model FeatureFlag
|
||||
- **devops**: Serializer Unit Test Suite re-written to Pytest for model FeatureFlag
|
||||
- **devops**: API Fields render Functional Test Suite re-written to Pytest for model FeatureFlag
|
||||
- **devops**: Model Functional Test Suite re-written to Pytest for model FeatureFlag
|
||||
- **devops**: API Metadata Functional Test Suite re-written to Pytest for model FeatureFlag
|
||||
- **api**: Remove old test suites no longer required model AuthToken
|
||||
- **api**: ViewSet Unit Test Suite re-written to Pytest for model AuthToken
|
||||
- **api**: Serializer Unit Test Suite re-written to Pytest for model AuthToken
|
||||
- **api**: API Fields render Functional Test Suite re-written to Pytest for model AuthToken
|
||||
- **api**: Model Functional Test Suite re-written to Pytest for model AuthToken
|
||||
- **api**: API Metadata Functional Test Suite re-written to Pytest for model AuthToken
|
||||
- **access**: Remove old test suites no longer required model Tenant
|
||||
- **access**: Serializer Unit Test Suite re-written to Pytest for model Tenant
|
||||
- **access**: API Fields render Functional Test Suite re-written to Pytest for model Tenant
|
||||
- **access**: Model Functional Test Suite re-written to Pytest for model Tenant
|
||||
- **access**: API Metadata Functional Test Suite re-written to Pytest for model Tenant
|
||||
- **settings**: Remove old test suites no longer required model UserSettings
|
||||
- **settings**: ViewSet Unit Test Suite re-written to Pytest for model UserSettings
|
||||
- **settings**: Serializer Unit Test Suite re-written to Pytest for model UserSettings
|
||||
- **settings**: API Fields render Functional Test Suite re-written to Pytest for model UserSettings
|
||||
- **settings**: Model Functional Test Suite re-written to Pytest for model UserSettings
|
||||
- **settings**: API Metadata Functional Test Suite re-written to Pytest for model UserSettings
|
||||
- **settings**: Remove old test suites no longer required model ExternalLink
|
||||
- **settings**: ViewSet Unit Test Suite re-written to Pytest for model ExternalLink
|
||||
- **settings**: Serializer Unit Test Suite re-written to Pytest for model ExternalLink
|
||||
- **settings**: API Fields render Functional Test Suite re-written to Pytest for model ExternalLink
|
||||
- **settings**: Model Functional Test Suite re-written to Pytest for model ExternalLink
|
||||
- **settings**: API Metadata Functional Test Suite re-written to Pytest for model ExternalLink
|
||||
- **settings**: Remove old test suites no longer required model AppSettings
|
||||
- **settings**: ViewSet Unit Test Suite re-written to Pytest for model AppSettings
|
||||
- **settings**: Serializer Unit Test Suite re-written to Pytest for model AppSettings
|
||||
- **settings**: API Fields render Functional Test Suite re-written to Pytest for model AppSettings
|
||||
- **settings**: Model Functional Test Suite re-written to Pytest for model AppSettings
|
||||
- **settings**: API Metadata Functional Test Suite re-written to Pytest for model AppSettings
|
||||
- **test**: remove xfail during `pytest_generate_tests` before parameterizing
|
||||
- **project_management**: ensure within fixtur kwargs are copied
|
||||
- **project_management**: Remove old test suites no longer required model ProjectType
|
||||
- **project_management**: ViewSet Unit Test Suite re-written to Pytest for model ProjectType
|
||||
- **project_management**: Serializer Unit Test Suite re-written to Pytest for model ProjectType
|
||||
- **project_management**: API Fields render Functional Test Suite re-written to Pytest for model ProjectType
|
||||
- **project_management**: Model Functional Test Suite re-written to Pytest for model ProjectType
|
||||
- **project_management**: API Metadata Functional Test Suite re-written to Pytest for model ProjectType
|
||||
- **project_management**: Remove old test suites no longer required model ProjectState
|
||||
- **project_management**: ViewSet Unit Test Suite re-written to Pytest for model ProjectState
|
||||
- **project_management**: Serializer Unit Test Suite re-written to Pytest for model ProjectState
|
||||
- **project_management**: API Fields render Functional Test Suite re-written to Pytest for model ProjectState
|
||||
- **project_management**: Model Functional Test Suite re-written to Pytest for model ProjectState
|
||||
- **project_management**: API Metadata Functional Test Suite re-written to Pytest for model ProjectState
|
||||
- **project_management**: Remove old test suites no longer required model ProjectMilestone
|
||||
- **project_management**: ViewSet Unit Test Suite re-written to Pytest for model ProjectMilestone
|
||||
- **project_management**: Serializer Unit Test Suite re-written to Pytest for model ProjectMilestone
|
||||
- **project_management**: API Fields render Functional Test Suite re-written to Pytest for model ProjectMilestone
|
||||
- **project_management**: Model Functional Test Suite re-written to Pytest for model ProjectMilestone
|
||||
- **project_management**: API Metadata Functional Test Suite re-written to Pytest for model ProjectMilestone
|
||||
- **project_management**: Remove old test suites no longer required model Project
|
||||
- **project_management**: ViewSet Unit Test Suite re-written to Pytest for model Project
|
||||
- **project_management**: Serializer Unit Test Suite re-written to Pytest for model Project
|
||||
- **project_management**: API Fields render Functional Test Suite re-written to Pytest for model Project
|
||||
- **project_management**: Model Functional Test Suite re-written to Pytest for model Project
|
||||
- **project_management**: API Metadata Functional Test Suite re-written to Pytest for model Project
|
||||
- **itim**: Remove old test suites no longer required model Service
|
||||
- **itim**: ViewSet Unit Test Suite re-written to Pytest for model Service
|
||||
- **itim**: Serializer Unit Test Suite re-written to Pytest for model Service
|
||||
- **itim**: API Fields render Functional Test Suite re-written to Pytest for model Service
|
||||
- **itim**: Model Functional Test Suite re-written to Pytest for model Service
|
||||
- **itim**: API Metadata Functional Test Suite re-written to Pytest for model Service
|
||||
- **itim**: Remove old test suites no longer required model Port
|
||||
- **itim**: ViewSet Unit Test Suite re-written to Pytest for model Port
|
||||
- **itim**: Serializer Unit Test Suite re-written to Pytest for model Port
|
||||
- **itim**: API Fields render Functional Test Suite re-written to Pytest for model Port
|
||||
- **itim**: Model Functional Test Suite re-written to Pytest for model Port
|
||||
- **itim**: API Metadata Functional Test Suite re-written to Pytest for model Port
|
||||
- **itim**: Remove old test suites no longer required model ClusterType
|
||||
- **itim**: ViewSet Unit Test Suite re-written to Pytest for model ClusterType
|
||||
- **itim**: Serializer Unit Test Suite re-written to Pytest for model ClusterType
|
||||
- **itim**: API Fields render Functional Test Suite re-written to Pytest for model ClusterType
|
||||
- **itim**: Model Functional Test Suite re-written to Pytest for model ClusterType
|
||||
- **itim**: API Metadata Functional Test Suite re-written to Pytest for model ClusterType
|
||||
- **itim**: Remove old test suites no longer required model Cluster
|
||||
- **itim**: ViewSet Unit Test Suite re-written to Pytest for model Cluster
|
||||
- **itim**: Serializer Unit Test Suite re-written to Pytest for model Cluster
|
||||
- **itim**: API Fields render Functional Test Suite re-written to Pytest for model Cluster
|
||||
- **itim**: Model Functional Test Suite re-written to Pytest for model Cluster
|
||||
- **itim**: API Metadata Functional Test Suite re-written to Pytest for model Cluster
|
||||
- **itam**: Remove old test suites no longer required model SoftwareVersion
|
||||
- **itam**: ViewSet Unit Test Suite re-written to Pytest for model SoftwareVersion
|
||||
- **itam**: Serializer Unit Test Suite re-written to Pytest for model SoftwareVersion
|
||||
- **itam**: Model Functional Test Suite re-written to Pytest for model SoftwareVersion
|
||||
- **itam**: API Fields render Functional Test Suite re-written to Pytest for model SoftwareVersion
|
||||
- **itam**: API Metadata Functional Test Suite re-written to Pytest for model SoftwareVersion
|
||||
- **itam**: Remove old test suites no longer required model SoftwareCategory
|
||||
- **itam**: ViewSet Unit Test Suite re-written to Pytest for model SoftwareCategory
|
||||
- **itam**: Serializer Unit Test Suite re-written to Pytest for model SoftwareCategory
|
||||
- **itam**: Model Functional Test Suite re-written to Pytest for model SoftwareCategory
|
||||
- **itam**: API Fields render Functional Test Suite re-written to Pytest for model SoftwareCategory
|
||||
- **itam**: API Metadata Functional Test Suite re-written to Pytest for model SoftwareCategory
|
||||
- **itam**: Remove old test suites no longer required model Software
|
||||
- **itam**: ViewSet Unit Test Suite re-written to Pytest for model Software
|
||||
- **itam**: Serializer Unit Test Suite re-written to Pytest for model Software
|
||||
- **itam**: Model Functional Test Suite re-written to Pytest for model Software
|
||||
- **itam**: API Fields render Functional Test Suite re-written to Pytest for model Software
|
||||
- **itam**: API Metadata Functional Test Suite re-written to Pytest for model Software
|
||||
- **itam**: Remove old test suites no longer required model OperatingSystemVersion
|
||||
- **itam**: ViewSet Unit Test Suite re-written to Pytest for model OperatingSystemVersion
|
||||
- **itam**: Serializer Unit Test Suite re-written to Pytest for model OperatingSystemVersion
|
||||
- **itam**: Model Functional Test Suite re-written to Pytest for model OperatingSystemVersion
|
||||
- **itam**: API Fields render Functional Test Suite re-written to Pytest for model OperatingSystemVersion
|
||||
- **itam**: API Metadata Functional Test Suite re-written to Pytest for model OperatingSystemVersion
|
||||
- **itam**: Remove old test suites no longer required model OperatingSystem
|
||||
- **itam**: ViewSet Unit Test Suite re-written to Pytest for model OperatingSystem
|
||||
- **itam**: Serializer Unit Test Suite re-written to Pytest for model OperatingSystem
|
||||
- **itam**: Model Functional Test Suite re-written to Pytest for model OperatingSystem
|
||||
- **itam**: API Fields render Functional Test Suite re-written to Pytest for model OperatingSystem
|
||||
- **itam**: API Metadata Functional Test Suite re-written to Pytest for model OperatingSystem
|
||||
- **itam**: API Metadata Functional Test Suite re-written to Pytest for model DeviceType
|
||||
- **itam**: Model Functional Test Suite re-written to Pytest for model DeviceType
|
||||
- **itam**: API Fields render Test Suite re-written to Pytest for model DeviceType
|
||||
- **itam**: Serializer Unit Test Suite re-written to Pytest for model DeviceType
|
||||
- **itam**: ViewSet Unit Test Suite re-written to Pytest for model DeviceModel
|
||||
- **itam**: API Metadata Functional Test Suite re-written to Pytest for model DeviceModel
|
||||
- **itam**: API Field Render Functional Test Suite re-written to PyTest for model Device
|
||||
- **itam**: Metadate Functional Test Suite re-enabled for model Device
|
||||
- **itam**: Viewset Unit Test Suite re-written to pytest for model Device
|
||||
- **itam**: Serializer Unit Test Suite re-enabled for model Device
|
||||
- **core**: API Render Unit Test Suite re-enabled for model Manufacturer
|
||||
- **core**: API Metadata Functional Test Suite re-enabled for model Manufacturer
|
||||
- **core**: Serializer Functional Test Suite re-enabled for model Manufacturer
|
||||
- **core**: ViewSet Test Suite re-written to pytest for model Manufacturer
|
||||
- **config_management**: ViewSet Test Suite re-written to pytest for model ConfigGroupSoftware
|
||||
- **config_management**: API fields Test Suite re-enalbed for model ConfigGroupSoftware
|
||||
- **config_management**: API Metadata Functional Test Suite for model ConfigGroupSoftware
|
||||
- **config_management**: Serializer Functional Test Suite Enabled for model ConfigGroupSoftware
|
||||
- **config_management**: Model Unit Test Suite re-written to pytest for model ConfigGroup
|
||||
- **config_management**: API Metadata Functional Test Suite re-written to pytest for model ConfigGroup
|
||||
- **assistance**: Serializer Unit Test Suite re-written to pytest for model KnowledgeBase
|
||||
- **assistance**: MetaData Unit Test Suite re-written to pytest for model KnowledgeBaseCategory
|
||||
- **assistance**: Serializer Unit Test Suite re-written to pytest for model KnowledgeBaseCategory
|
||||
- **assistance**: ViewSet Unit Test Suite re-written to pytest for model KnowledgeBaseCategory
|
||||
- **assistance**: Serializer Unit Test Suite re-written to pytest for model KnowledgeBaseCategory
|
||||
- **assistance**: Serializer Unit TestSuite re-written to pytest for model KnowledgeBase
|
||||
- **assistance**: ViewSet TestSuite re-written to pytest for model KnowledgeBase
|
||||
- **access**: ViewSet TestSuite re-written to pytest for model Tenant
|
||||
- **access**: ViewSet TestSuite re-written to pytest for model Person
|
||||
- **access**: ViewSet TestSuite re-written to pytest for model Entity
|
||||
- **access**: ViewSet TestSuite re-written to pytest for model Contact
|
||||
- **access**: ViewSet TestSuite re-written to pytest for model Company
|
||||
- **api**: migrate Common ViewSet unittest.mock to mocker
|
||||
- **api**: migrate Common ViewSet Unit Test Suite attribute to use test case `unit_class`
|
||||
- **api**: Converted Common ViewSet Unit Test Suite to use Pytest
|
||||
- **api**: partial conversion to pytest for Common ViewSet Unit Test Suite
|
||||
- **api**: Rename create Serializer unit test to `is_valid`
|
||||
- **base**: normalize empty/not used to be `models.NOT_PROVIDED`
|
||||
- **base**: adjust functional model test to use fixture kwargs
|
||||
- **api**: Update Test Suite for AuthToken model
|
||||
- **tests**: Unskip tests that'll work now due to model inheritance change
|
||||
- **api**: Update Test Suite for AuthToken model
|
||||
- **api**: Update URL route name for Role AuthToken
|
||||
- **api**: Switch to inherit from Centurion model for model AuthToken
|
||||
- **access**: When adding model role via api, status is 201/created
|
||||
- **itim**: Update Test Suite for TicketCommentSolution model
|
||||
- **itim**: Update Test Suite for TicketSLM model
|
||||
- **itim**: Update Test Suite for TicketRequest model
|
||||
- **core**: Update Test Suite for TicketBase model
|
||||
- **core**: Update Test Suite for TicketCommentSolution model
|
||||
- **core**: Update Test Suite for TicketCommentAction model
|
||||
- **core**: Update Test Suite for TicketCommentBase model
|
||||
- **core**: Initial Update Test Suite for TicketCommentBase model
|
||||
- **core**: Update Tests to cater for inheritence changes
|
||||
- **itim**: Update Test Suite for RequestTicket model
|
||||
- **itim**: Update Test Suite for SLMTicket model
|
||||
- **itim**: Update Test Suite for SLMTicket model
|
||||
- **core**: Update Test Suite for TicketBase model
|
||||
- **core**: Update Test Suite for TicketBase model
|
||||
- **core**: Switch to inherit from Centurion model for model TicketBase
|
||||
- **core**: Switch to inherit from Centurion model for model SLMTicketBase
|
||||
- **core**: Update URL route name for Role TicketCommentBase
|
||||
- **core**: Switch to inherit from Centurion model for model TicketCommentBase
|
||||
- **core**: Update URL route name for Role TicketBase
|
||||
- **core**: Switch to inherit from Centurion model for model TicketBase
|
||||
- **core**: Add fn get_organization to centurion mixin
|
||||
- **access**: Adjust add permission test for model Role
|
||||
- **access**: Migrations for Inheritance change for Role model
|
||||
- **access**: Update URL route name for Role model
|
||||
- **access**: Update Test Suite for Role model
|
||||
- **access**: Switch to inherit from Centurion model for model Role
|
||||
- Asset and ITAM Asset must use url kwarg model_name not asset_model
|
||||
- **accounting**: Update existing tests to work due to model inheritance changes
|
||||
- **itam**: Update URL route name for ITAMAssetBase model
|
||||
- **itam**: Update Test Suite for ITAMAssetBase model
|
||||
- **itam**: Switch to inherit from Centurion model for model ITAMAssetBase
|
||||
- **accounting**: Switch to inherit from Centurion model for model AssetBase
|
||||
- **accounting**: Update URL route name for AssetBase model
|
||||
- **accounting**: Update Test Suite for AssetBase model
|
||||
- **accounting**: Switch to inherit from Centurion model for model AssetBase
|
||||
- **api**: dont query db for instance, use existing from response
|
||||
- **api**: additional perms tests if they exist must be inc first
|
||||
- **devops**: remove ViewSet `get_queryset` function
|
||||
- **access**: Update Entity model ViewSet attribute `model_kwarg` to `model_name`
|
||||
- **access**: Update Entity model ViewSet to inherit from submodel-rewrite
|
||||
- **access**: Update Test Suite for Employee model
|
||||
- **access**: Update Test Suite for Person model
|
||||
- **access**: Update Test Suite for Contact model
|
||||
- **access**: Update Test Suite for Company model
|
||||
- **access**: Update URL route name for Entity model
|
||||
- **access**: Update Test Suite for Entity model
|
||||
- **access**: Update is_tenancy_object to check for CenturionModel
|
||||
- **access**: For request middleware, use filter and first object so that testing can occur when mre than one exists
|
||||
- **settings**: Update URL route name for UserSettings model
|
||||
- **settings**: Update Test Suite for ExternalLink model
|
||||
- **settings**: Update URL route name for ExternalLink model
|
||||
- **settings**: Update Test Suite for ExternalLink model
|
||||
- **settings**: Update URL route name for AppSettings model
|
||||
- **settings**: Update Test Suite for AppSettings model
|
||||
- **project_management**: Update URL route name for ProjectType model
|
||||
- **project_management**: Update Test Suite for ProjectType model
|
||||
- **project_management**: Update URL route name for ProjectState model
|
||||
- **project_management**: Update Test Suite for ProjectState model
|
||||
- **project_management**: Update URL route name for ProjectMilestone model
|
||||
- **project_management**: Update Test Suite for ProjectMilestone model
|
||||
- **project_management**: Update URL route name for Project model
|
||||
- **project_management**: Update Test Suite for Project model
|
||||
- **itim**: Update URL route name for Service model
|
||||
- **itim**: Update Test Suite for Service model
|
||||
- **itim**: Update URL route name for Port model
|
||||
- **itim**: Update Test Suite for Port model
|
||||
- **itim**: Update URL route name for ClusterType model
|
||||
- **itim**: Update Test Suite for ClusterType model
|
||||
- **itim**: Update URL route name for Cluster model
|
||||
- **itim**: Update Test Suite for Cluster model
|
||||
- **itam**: Update Test Suite for SoftwareVersion model
|
||||
- **itam**: Update URL route name for SoftwareVersion model
|
||||
- **itam**: Update Test Suite for SoftwareCategory model
|
||||
- **itam**: Update URL route name for SoftwareCategory model
|
||||
- cater for dev that does not exist in test cleanup
|
||||
- **itam**: Update Test Suite for Software model
|
||||
- **itam**: Update URL route name for Software model
|
||||
- **itam**: Update Test Suite for OperatingSystemVersion model
|
||||
- **itam**: Update Test Suite for OperatingSystem model
|
||||
- **itam**: Update URL route name for DeviceSoftware model
|
||||
- **itam**: Update Test Suite for DeviceSoftware model
|
||||
- **itam**: Update Test Suite for DeviceDeviceOperatingSystem model
|
||||
- **itam**: Update URL route for DeviceDeviceOperatingSystem model
|
||||
- **itam**: Migration for updating model inheritance for DeviceDeviceOperatingSystem model
|
||||
- **itam**: Updated Unit model test suite for DeviceType model
|
||||
- **devops**: Updated Unit model test suite for DeviceModel model
|
||||
- **devops**: Migration for updating model inheritance for DeviceModel model
|
||||
- **itam**: Updated Unit model test suite for Device model
|
||||
- **devops**: Updated Unit model test ssuite for SoftwareEnabledFeatureFlag model
|
||||
- **devops**: Migration for updating model inheritance for SoftwareEnabledFeatureFlag model
|
||||
- **devops**: Update url route basename for SoftwareEnabledFeatureFlag model
|
||||
- **tests**: make all `parameterized_` vars properties
|
||||
- **core**: adjust CenturionSubModel to not be it's own inheritable class
|
||||
- **core**: Move CenturionModel logic to Mixin
|
||||
- **core**: rename mixin -> mixins
|
||||
- **base**: model instancxe code de-duplicated
|
||||
- **config_management**: Add ConfigGroupHost Model Tests
|
||||
- **config_management**: Add ConfigGroupSoftware Model Tests
|
||||
- **config_management**: Add ConfigGroup Model Tests
|
||||
- **assistance**: Refactor KnowledgeBaseCategory Unit model tests
|
||||
- **assistance**: Update KnowledgeBase Unit viewset url basename
|
||||
- **assistance**: Refactor KnowledgeBase Unit model tests
|
||||
- **assistance**: Add new history and notes Serializer for KnowledgeBase model
|
||||
- **assistance**: Add new history and notes Serializer for KnowledgeBaseCategory model
|
||||
- **assistance**: Change KnowledgeBaseCategory model inheritance TenancyObject -> CenturionModel
|
||||
- **assistance**: Change KnowledgeBase model inheritance TenancyObject -> CenturionModel
|
||||
- **assistance**: MV kb category model to its own file
|
||||
- **tests**: Create global model fixtures
|
||||
- **devops**: Switch FeatureFlag model unit tests to CenturionModel
|
||||
- **settings**: move url routes from core.urls to own module `urls_api.py`
|
||||
- **project_management**: move url routes from core.urls to own module `urls_api.py`
|
||||
- **itim**: move url routes from core.urls to own module `urls_api.py`
|
||||
- **itam**: move url routes from core.urls to own module `urls_api.py`
|
||||
- **core**: move url routes from core.urls to own module `urls_api.py`
|
||||
- **config_management**: move url routes from core.urls to own module `urls_api.py`
|
||||
- **assistance**: move url routes from core.urls to own module `urls_api.py`
|
||||
- **access**: move url routes from core.urls to own module `urls_api.py`
|
||||
- **api**: Update Common ViewSet methds for re-write
|
||||
- **devops**: Switch GitGroup Model to CenturionModel
|
||||
- **core**: Loading of meta models should not be hidden behind program start ags
|
||||
- **core**: To obtain audit_values loop through model fields
|
||||
- rejig whats in each inherited centurion model
|
||||
- **access**: prefetch org with tenancy object
|
||||
- **core**: Relocate history model class
|
||||
- **base**: rename app to centurion
|
||||
|
||||
### Tests
|
||||
|
||||
- **core**: Notes Meta Models API Permissions Test cases for All Notes Models
|
||||
- Add initial integration tests
|
||||
- **docker**: Add compose setup for integration testing
|
||||
- **itam**: ViewSet Unit Test Suite added for model DeviceType
|
||||
- **itam**: Serializer UnitTest Suite added for model DeviceModel
|
||||
- **itam**: API Fields render Functional Test Suite added for model DeviceModel
|
||||
- **itam**: Model Functional Test Suite added for model DeviceModel
|
||||
- **itam**: Refactor failing tests to cater for uniqueness so they pass
|
||||
- **itam**: Model Functional Test Suite aded for model Device
|
||||
- **config_management**: ViewSet Unit Test Suite re-written to pytest for model ConfigGroup
|
||||
- **config_management**: Serializer Unit Test Suite re-written to pytest for model ConfigGroup
|
||||
- **config_management**: Model Functional Test Suite re-written to pytest for model ConfigGroup
|
||||
- **config_management**: API Field Render Functional Test Suite re-written to pytest for model ConfigGroup
|
||||
- **assistance**: API Field Render Functional Test Suite re-written to pytest for model KnowledgeBaseCategory
|
||||
- **assistance**: Model Functional Test Suite re-written to pytest for model KnowledgeBaseCategory
|
||||
- **assistance**: Model Functional Test Suite re-written to pytest for model KnowledgeBase
|
||||
- **assistance**: API Fields Render Functional Test Suite re-written to pytest for model KnowledgeBase
|
||||
- **api**: SubModel ViewSet Test Suite to test re-written class
|
||||
- **api**: Dont test a django object that has not been customised
|
||||
- **access**: Initial ViewSet Unit Test Suite for Entity Model
|
||||
- **access**: Add Serializer unit test suit for model Role
|
||||
- **access**: Add Serializer unit test suit for model Person
|
||||
- **access**: Add Serializer unit test suit for model Entity
|
||||
- **access**: Add Serializer unit test suit for model Contact
|
||||
- **access**: Add Serializer unit test suit for model Company
|
||||
- **itim**: Refactor TicketSLM model API Fields render test Suite to PyTest
|
||||
- **itim**: Refactor TicketRequest model API Fields render test Suite to PyTest
|
||||
- **core**: Refactor TicketBase model API Fields render test Suite to PyTest
|
||||
- **api**: Refactor Test Suite for API Fields render tests to PyTest
|
||||
- **itam**: Refactor ITAMAssetBase model API Fields render test Suite to PyTest
|
||||
- **accounting**: Refactor AssetBase model API Fields render test Suite to PyTest
|
||||
- **core**: Refactor TicketCommentSolution model API Fields render test Suite to PyTest
|
||||
- **core**: Refactor TicketCommentAction model API Fields render test Suite to PyTest
|
||||
- **core**: Refactor TicketCommentBase model API Fields render test Suite to PyTest
|
||||
- **human_resources**: Refactor Employee model API Fields render test Suite to PyTest
|
||||
- **access**: Refactor Person model API Fields render test Suite to PyTest
|
||||
- **access**: Refactor Entity model API Fields render test Suite to PyTest
|
||||
- **access**: Refactor Contact model API Fields render test Suite to PyTest
|
||||
- **access**: Refactor Company model API Fields render test Suite to PyTest
|
||||
- **devops**: Adjust functional model test to use fixture kwargs
|
||||
- Ensure when obj created via serializer calls full_clean
|
||||
- Ensure Clean methods called
|
||||
- Test case for model field type
|
||||
- **fixture**: if item already exists, when fetching remove modified field from query if not found with
|
||||
- **access**: Model Role is not usable within global org, remove test
|
||||
- **devops**: skip Model History entry test as it should be done as part of serializer and viewset
|
||||
- **devops**: update no_org_serializer test so it works for model SoftwareEnableFeatureFlag
|
||||
- **itam**: Model DeviceOperatingSystem is not multi-org based skip those tests
|
||||
- **settings**: Model UserSettings does not allowing adding rows, skip test
|
||||
- **settings**: Model AppSettings does not allowing adding rows, skip test
|
||||
- **fixture**: Ensure _meta attribute exists when cleaning up models prior to attempting to use
|
||||
- **devops**: SoftwareEnableFeatureFlagging model does not use global org, so dont test global org return
|
||||
- **api**: when testing create object, remove the actual created object prior to testing the add
|
||||
- **fixture**: when creating object and it exists, rtn that object
|
||||
- **devops**: If test publically accessable, dont test by user org only as test is NA
|
||||
- **settings**: UserSettings perms tests are for the user that is accessing them
|
||||
- **settings**: UserSettings perms tests are not org based, skip those tests
|
||||
- **settings**: AppSettings perms tests are not org based, skip those tests
|
||||
- **settings**: for api checks for model AppSettings, make user super_user
|
||||
- **settings**: Exclude inter-org tests for model AppSettings
|
||||
- **settings**: Remove old API Permission tests no longer required
|
||||
- **settings**: Ensure ExternalLink model hasrequired field template added
|
||||
- **api**: if model lacks list endpoint, check if method alllowed for test cases for Functional API perms test suite
|
||||
- **api**: if model lacks organization field, xfail returned orgs test cases for Functional API perms test suite
|
||||
- Ensure service fixture assosiates with device
|
||||
- **api**: if model lacks organization field, xfail returned orgs test cases for Functional API perms test suite
|
||||
- Add depreciated models to be excluded from coverage
|
||||
- **api**: Update Functional API Permission test suite to cater for public RO endpoints
|
||||
- **core**: Ensure model mehod `get_url_kwargs` returns a dict for all Centurion Models
|
||||
- **devops**: Add GitLabRepository Unit Model test suite
|
||||
- **devops**: Add GitHubRepository Unit Model test suite
|
||||
- **devops**: Add GitRepository Unit Model test suite
|
||||
- **devops**: Add Checkin Unit Model test suite
|
||||
- **devops**: correct GitGroup Unit model test suite
|
||||
- **devops**: correct FeatureFlag Unit model test suite
|
||||
- **core**: Add TicketCommentCategory Unit model test suite
|
||||
- **core**: Add TicketCategory Unit model test suite
|
||||
- **core**: Add Manufacturer Unit model test suite
|
||||
- **access**: Add Tenant Unit serializer test suite
|
||||
- Add initial unit serializer test suite
|
||||
- **access**: Update Tenant URL route basename again
|
||||
- **itam**: Updated Unit model test for Device Model
|
||||
- **access**: Update Tenant URL route basename
|
||||
- **access**: Tenant Model Tests
|
||||
- **api**: Update Functional API Permissions to support listview models with kwargs
|
||||
- **api**: exclude model `ConfigGroupHosts` from api permission tests as it has no endpoint
|
||||
- **api**: API Permissions Functional test to supprt name as unique field
|
||||
- **config_management**: Completed ConfigGroupSoftware Model Tests
|
||||
- **config_management**: Completed ConfigGroup Model Tests
|
||||
- **config_management**: Completed ConfigGroupHost Model Tests
|
||||
- **core**: mock the user object within the model context
|
||||
- **core**: creating a model is a functional not unit test
|
||||
- **devops**: re-implement temp removed test suites.
|
||||
- **api**: API Permissions Auto-Creator test suite
|
||||
- **devops**: Add GitGroup API Permissions tests
|
||||
- **core**: Add fixtures for api permission tests
|
||||
- **core**: rewrite api permissions test suite to use pytest and fixtures
|
||||
- **core**: Ensure Method clean_fields functions for CenturionNotesModel
|
||||
- **core**: Function Model test suite for CenturionModelNote Meta Models
|
||||
- **core**: Interim Unit Model test suite for CenturionModelNote Meta Models
|
||||
- **core**: Interim Unit Model test suite for CenturionModelNote
|
||||
- **core**: Dynamic Unit Test Suites for Meta Models AuditHistory
|
||||
- **core**: Unit Test Centurion Model method `__str__`
|
||||
- **core**: Unit Test Centurion Model method `get_url_kwargs`
|
||||
- **core**: Unite Tesxt Centurion Model method `get_url` attr `_is_submodel` set
|
||||
- **core**: Unite Tesxt Centurion Model method `get_url` attr `model_name` set
|
||||
- **core**: Ensure model that has audit enableed has audit model
|
||||
- **core**: Add Functional model Test Suite for CenturionAuditModel
|
||||
- **devops**: Ensure that a Github group cant have a parent/"be nested"
|
||||
- **devops**: Ensure that when create a child git group that the tenancy matches the parent git group
|
||||
- **devops**: Add Functional model Test Suite
|
||||
- **core**: Add Base Centurion model Functional Test Suite
|
||||
- **access**: Add Base Tenancy model Functional Test Suite
|
||||
- **base**: Add Base model Functional Test Suite
|
||||
- **core**: Model Unit Tests for AuditHistory `get_model_history` method
|
||||
- **core**: reset vals so as not to fuck other tests over
|
||||
- **core**: Correct test for method `get_audit_values` for `CenturionAbstractModel`
|
||||
- **devops**: Initial Model Unit tests for GitGroup
|
||||
- **core**: Add field `model_notes` as an excluded field for AuditModels
|
||||
- **core**: Remaining Unit Model Test Cases for CenturionAuditMeta Model
|
||||
- **core**: Initial Unit Model Test Cases for CenturionAuditMeta Model
|
||||
- **core**: Unit Model Test Cases for CenturionSubAbstract model
|
||||
- **core**: Initial Unit Model Test Cases for CenturionAudit Model
|
||||
- **core**: Unit test cases for Centurion get_url relative + non-relative
|
||||
- **access**: Unit Model Tests for TenancyAbstractModel
|
||||
- **base**: Unit Common Model test cases suite
|
||||
- **base**: Unit Common Class test cases suite
|
||||
- **access**: Unit Model Tests for TenancyAbstractModel
|
||||
|
||||
## 1.18.0 (2025-07-03)
|
||||
|
||||
### feat
|
||||
|
@ -1,4 +1,4 @@
|
||||
## Version 1.18.0
|
||||
## Version 1.19.0
|
||||
|
||||
- Added new model for History
|
||||
|
||||
@ -18,7 +18,7 @@
|
||||
|
||||
- Removed Django UI
|
||||
|
||||
[UI](https://github.com/nofusscomputing/centurion_erp) must be deployed seperatly.
|
||||
[UI](https://github.com/nofusscomputing/centurion_erp_ui) must be deployed seperatly.
|
||||
|
||||
- Removed API v1
|
||||
|
||||
|
@ -1,9 +1,10 @@
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.models import (
|
||||
ContentType,
|
||||
Permission
|
||||
)
|
||||
from django.conf import settings
|
||||
from django.db.models import QuerySet
|
||||
|
||||
|
||||
def permission_queryset():
|
||||
@ -61,47 +62,66 @@ def permission_queryset():
|
||||
|
||||
if not settings.RUNNING_TESTS:
|
||||
|
||||
models = apps.get_models()
|
||||
try:
|
||||
# This blocks purpose is to cater for fresh install
|
||||
# so that the app does not crash before the DB is setup.
|
||||
|
||||
for model in models:
|
||||
models = apps.get_models()
|
||||
|
||||
if(
|
||||
not str(model._meta.object_name).endswith('AuditHistory')
|
||||
and not str(model._meta.model_name).lower().endswith('history')
|
||||
):
|
||||
# check `endswith('history')` can be removed when the old history models are removed
|
||||
continue
|
||||
|
||||
content_type = ContentType.objects.get(
|
||||
app_label = model._meta.app_label,
|
||||
model = model._meta.model_name
|
||||
)
|
||||
|
||||
permissions = Permission.objects.filter(
|
||||
content_type = content_type,
|
||||
)
|
||||
|
||||
for permission in permissions:
|
||||
for model in models:
|
||||
|
||||
if(
|
||||
not permission.codename == 'view_' + str(model._meta.model_name)
|
||||
and str(model._meta.object_name).endswith('AuditHistory')
|
||||
):
|
||||
exclude_permissions += [ permission.codename ]
|
||||
|
||||
elif(
|
||||
not str(model._meta.object_name).endswith('AuditHistory')
|
||||
and str(model._meta.model_name).lower().endswith('history')
|
||||
and not str(model._meta.model_name).lower().endswith('history')
|
||||
):
|
||||
# This `elif` can be removed when the old history models are removed
|
||||
# check `endswith('history')` can be removed when the old history models are removed
|
||||
continue
|
||||
|
||||
exclude_permissions += [ permission.codename ]
|
||||
content_type = ContentType.objects.get(
|
||||
app_label = model._meta.app_label,
|
||||
model = model._meta.model_name
|
||||
)
|
||||
|
||||
permissions = Permission.objects.filter(
|
||||
content_type = content_type,
|
||||
)
|
||||
|
||||
for permission in permissions:
|
||||
|
||||
if(
|
||||
not permission.codename == 'view_' + str(model._meta.model_name)
|
||||
and str(model._meta.object_name).endswith('AuditHistory')
|
||||
):
|
||||
exclude_permissions += [ permission.codename ]
|
||||
|
||||
elif(
|
||||
not str(model._meta.object_name).endswith('AuditHistory')
|
||||
and str(model._meta.model_name).lower().endswith('history')
|
||||
):
|
||||
# This `elif` can be removed when the old history models are removed
|
||||
|
||||
exclude_permissions += [ permission.codename ]
|
||||
|
||||
|
||||
return Permission.objects.select_related('content_type').filter(
|
||||
content_type__app_label__in = centurion_apps,
|
||||
).exclude(
|
||||
content_type__model__in = exclude_models
|
||||
).exclude(
|
||||
codename__in = exclude_permissions
|
||||
)
|
||||
return Permission.objects.select_related('content_type').filter(
|
||||
content_type__app_label__in = centurion_apps,
|
||||
).exclude(
|
||||
content_type__model__in = exclude_models
|
||||
).exclude(
|
||||
codename__in = exclude_permissions
|
||||
)
|
||||
|
||||
except:
|
||||
pass
|
||||
|
||||
return QuerySet()
|
||||
|
||||
else:
|
||||
|
||||
return Permission.objects.select_related('content_type').filter(
|
||||
content_type__app_label__in = centurion_apps,
|
||||
).exclude(
|
||||
content_type__model__in = exclude_models
|
||||
).exclude(
|
||||
codename__in = exclude_permissions
|
||||
)
|
||||
|
526
app/access/migrations/0011_remove_entitynotes_model_and_more.py
Normal file
526
app/access/migrations/0011_remove_entitynotes_model_and_more.py
Normal file
@ -0,0 +1,526 @@
|
||||
# Generated by Django 5.1.10 on 2025-08-15 03:21
|
||||
|
||||
import access.models.tenancy_abstract
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0010_company_alter_entity_entity_type_alter_person_dob_and_more"),
|
||||
("core", "0024_centurionaudit_centurionmodelnote_and_more"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name="entity",
|
||||
name="is_global",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="tenant",
|
||||
name="slug",
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="entity",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="entity",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="entity",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="role",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="role",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="role",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="tenant",
|
||||
name="manager",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="Manager for this Tenancy",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Manager",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="tenant",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="CompanyAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.company",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Company History",
|
||||
"verbose_name_plural": "Company Histories",
|
||||
"db_table": "access_company_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="CompanyCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.company",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Company Note",
|
||||
"verbose_name_plural": "Company Notes",
|
||||
"db_table": "access_company_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ContactAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.contact",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Contact History",
|
||||
"verbose_name_plural": "Contact Histories",
|
||||
"db_table": "access_contact_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ContactCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.contact",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Contact Note",
|
||||
"verbose_name_plural": "Contact Notes",
|
||||
"db_table": "access_contact_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="EntityAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="access.entity",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Entity History",
|
||||
"verbose_name_plural": "Entity Histories",
|
||||
"db_table": "access_entity_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="EntityCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.entity",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Entity Note",
|
||||
"verbose_name_plural": "Entity Notes",
|
||||
"db_table": "access_entity_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="PersonAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.person",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Person History",
|
||||
"verbose_name_plural": "Person Histories",
|
||||
"db_table": "access_person_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="PersonCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.person",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Person Note",
|
||||
"verbose_name_plural": "Person Notes",
|
||||
"db_table": "access_person_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="RoleAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="access.role",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Role History",
|
||||
"verbose_name_plural": "Role Histories",
|
||||
"db_table": "access_role_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="RoleCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.role",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Role Note",
|
||||
"verbose_name_plural": "Role Notes",
|
||||
"db_table": "access_role_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="TenantAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="access.tenant",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Tenant History",
|
||||
"verbose_name_plural": "Tenant Histories",
|
||||
"db_table": "access_tenant_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="TenantCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Tenant Note",
|
||||
"verbose_name_plural": "Tenant Notes",
|
||||
"db_table": "access_tenant_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name="EntityHistory",
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name="EntityNotes",
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name="RoleHistory",
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name="RoleNotes",
|
||||
),
|
||||
]
|
@ -1,110 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-06 01:41
|
||||
|
||||
import access.models.tenancy_abstract
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0010_company_alter_entity_entity_type_alter_person_dob_and_more"),
|
||||
("core", "0028_delete_history"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name="team",
|
||||
name="is_global",
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="team",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="team",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="TeamAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="access.team",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Team History",
|
||||
"verbose_name_plural": "Team Histories",
|
||||
"db_table": "access_team_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit", models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="TeamCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.team",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Team Note",
|
||||
"verbose_name_plural": "Team Notes",
|
||||
"db_table": "access_team_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote", models.Model),
|
||||
)
|
||||
]
|
@ -1,102 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-06 01:43
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0011_remove_team_is_global_model_notes_and_more"),
|
||||
("core", "0028_delete_history"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="teamusers",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="teamusers",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="TeamUsersAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="access.teamusers",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Team User History",
|
||||
"verbose_name_plural": "Team User Histories",
|
||||
"db_table": "access_teamusers_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit", models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="TeamUsersCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.teamusers",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Team User Note",
|
||||
"verbose_name_plural": "Team User Notes",
|
||||
"db_table": "access_teamusers_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote", models.Model),
|
||||
),
|
||||
]
|
@ -1,16 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-06 05:22
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0012_teamusers_model_notes_alter_teamusers_id_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel(
|
||||
name="TeamUsersAuditHistory",
|
||||
),
|
||||
]
|
@ -1,16 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-07 09:05
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0013_delete_teamusersaudithistory"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel(
|
||||
name="TeamUsersCenturionModelNote",
|
||||
),
|
||||
]
|
@ -1,75 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-07 10:10
|
||||
|
||||
import access.models.team
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0014_delete_teamuserscenturionmodelnote"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name="teamcenturionmodelnote",
|
||||
name="centurionmodelnote_ptr",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="teamcenturionmodelnote",
|
||||
name="model",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="teamusers",
|
||||
name="model_notes",
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="team",
|
||||
name="is_global",
|
||||
field=models.BooleanField(
|
||||
default=False,
|
||||
help_text="Is this a global object?",
|
||||
verbose_name="Global Object",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="team",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
default=None,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="team",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="access.tenant",
|
||||
validators=[access.models.team.Team.validatate_organization_exists],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="teamusers",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of this Team User",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name="TeamAuditHistory",
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name="TeamCenturionModelNote",
|
||||
),
|
||||
]
|
@ -1,112 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-08 04:18
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
(
|
||||
"access",
|
||||
"0015_remove_teamcenturionmodelnote_centurionmodelnote_ptr_and_more",
|
||||
),
|
||||
("core", "0031_remove_ticketcategory_is_global_and_more"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name="tenant",
|
||||
name="slug",
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="tenant",
|
||||
name="manager",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="Manager for this Tenancy",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Manager",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="tenant",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="TenantAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="access.tenant",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Tenant History",
|
||||
"verbose_name_plural": "Tenant Histories",
|
||||
"db_table": "access_tenant_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit", models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="TenantCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Tenant Note",
|
||||
"verbose_name_plural": "Tenant Notes",
|
||||
"db_table": "access_tenant_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote", models.Model),
|
||||
),
|
||||
]
|
@ -1,19 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-17 07:27
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0016_remove_tenant_slug_alter_tenant_manager_and_more"),
|
||||
("core", "0033_alter_ticketcommentcategory_parent_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel(
|
||||
name="EntityHistory",
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name="EntityNotes",
|
||||
),
|
||||
]
|
@ -1,253 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-17 07:32
|
||||
|
||||
import access.models.tenancy_abstract
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0017_remove_entitynotes_model_and_more"),
|
||||
("core", "0033_alter_ticketcommentcategory_parent_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name="entity",
|
||||
name="is_global",
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="entity",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="entity",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="entity",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ContactAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.contact",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Contact History",
|
||||
"verbose_name_plural": "Contact Histories",
|
||||
"db_table": "access_contact_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ContactCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.contact",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Contact Note",
|
||||
"verbose_name_plural": "Contact Notes",
|
||||
"db_table": "access_contact_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="EntityAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="access.entity",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Entity History",
|
||||
"verbose_name_plural": "Entity Histories",
|
||||
"db_table": "access_entity_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="EntityCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.entity",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Entity Note",
|
||||
"verbose_name_plural": "Entity Notes",
|
||||
"db_table": "access_entity_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="PersonAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.person",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Person History",
|
||||
"verbose_name_plural": "Person Histories",
|
||||
"db_table": "access_person_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="PersonCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.person",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Person Note",
|
||||
"verbose_name_plural": "Person Notes",
|
||||
"db_table": "access_person_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
]
|
@ -1,81 +0,0 @@
|
||||
# Generated by Django 5.1.10 on 2025-07-06 10:38
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0018_remove_entity_is_global_alter_entity_id_and_more"),
|
||||
("core", "0033_alter_ticketcommentcategory_parent_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="CompanyAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.company",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Company History",
|
||||
"verbose_name_plural": "Company Histories",
|
||||
"db_table": "access_company_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="CompanyCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.company",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Company Note",
|
||||
"verbose_name_plural": "Company Notes",
|
||||
"db_table": "access_company_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
]
|
@ -1,56 +0,0 @@
|
||||
# Generated by Django 5.1.10 on 2025-07-12 07:20
|
||||
|
||||
import access.models.tenancy_abstract
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0019_companyaudithistory_companycenturionmodelnote"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="role",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="role",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="role",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name="RoleHistory",
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name="RoleNotes",
|
||||
),
|
||||
]
|
@ -1,81 +0,0 @@
|
||||
# Generated by Django 5.1.10 on 2025-07-12 08:50
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0020_remove_rolenotes_model_and_more"),
|
||||
("core", "0033_alter_ticketcommentcategory_parent_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="RoleAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="access.role",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Role History",
|
||||
"verbose_name_plural": "Role Histories",
|
||||
"db_table": "access_role_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="RoleCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.role",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Role Note",
|
||||
"verbose_name_plural": "Role Notes",
|
||||
"db_table": "access_role_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
]
|
@ -0,0 +1,104 @@
|
||||
import pytest
|
||||
|
||||
from django.test import Client
|
||||
|
||||
|
||||
|
||||
class AdditionalTestCases:
|
||||
|
||||
|
||||
def test_permission_change(self, model_instance, api_request_permissions):
|
||||
""" Check correct permission for change
|
||||
|
||||
Make change with user who has change permission
|
||||
"""
|
||||
|
||||
client = Client()
|
||||
|
||||
client.force_login( api_request_permissions['user']['change'] )
|
||||
|
||||
kwargs = self.kwargs_create_item.copy()
|
||||
kwargs.update({
|
||||
'organization': api_request_permissions['tenancy']['user'],
|
||||
'model': api_request_permissions['tenancy']['user']
|
||||
})
|
||||
|
||||
change_item = model_instance(
|
||||
kwargs_create = kwargs,
|
||||
)
|
||||
|
||||
response = client.patch(
|
||||
path = change_item.get_url( many = False ),
|
||||
data = self.change_data,
|
||||
content_type = 'application/json'
|
||||
)
|
||||
|
||||
if response.status_code == 405:
|
||||
pytest.xfail( reason = 'ViewSet does not have this request method.' )
|
||||
|
||||
assert response.status_code == 200, response.content
|
||||
|
||||
|
||||
|
||||
def test_permission_delete(self, model_instance, api_request_permissions):
|
||||
""" Check correct permission for delete
|
||||
|
||||
Delete item as user with delete permission
|
||||
"""
|
||||
|
||||
client = Client()
|
||||
|
||||
client.force_login( api_request_permissions['user']['delete'] )
|
||||
|
||||
kwargs = self.kwargs_create_item
|
||||
kwargs.update({
|
||||
'organization': api_request_permissions['tenancy']['user'],
|
||||
'model': api_request_permissions['tenancy']['user']
|
||||
})
|
||||
|
||||
delete_item = model_instance(
|
||||
kwargs_create = kwargs
|
||||
)
|
||||
|
||||
response = client.delete(
|
||||
path = delete_item.get_url( many = False ),
|
||||
)
|
||||
|
||||
if response.status_code == 405:
|
||||
pytest.xfail( reason = 'ViewSet does not have this request method.' )
|
||||
|
||||
assert response.status_code == 204, response.content
|
||||
|
||||
def test_permission_view(self, model_instance, api_request_permissions):
|
||||
""" Check correct permission for view
|
||||
|
||||
Attempt to view as user with view permission
|
||||
"""
|
||||
|
||||
client = Client()
|
||||
|
||||
client.force_login( api_request_permissions['user']['view'] )
|
||||
|
||||
kwargs = self.kwargs_create_item
|
||||
kwargs.update({
|
||||
'organization': api_request_permissions['tenancy']['user'],
|
||||
'model': api_request_permissions['tenancy']['user']
|
||||
})
|
||||
|
||||
view_item = model_instance(
|
||||
kwargs_create = kwargs
|
||||
)
|
||||
|
||||
response = client.get(
|
||||
path = view_item.get_url( many = False )
|
||||
)
|
||||
|
||||
if response.status_code == 405:
|
||||
pytest.xfail( reason = 'ViewSet does not have this request method.' )
|
||||
|
||||
assert response.status_code == 200, response.content
|
||||
|
||||
|
||||
@pytest.mark.xfail( reason = 'model is not global based')
|
||||
def test_returned_data_from_user_and_global_organizations_only(self ):
|
||||
assert False
|
@ -1,94 +0,0 @@
|
||||
import django
|
||||
import pytest
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
from access.serializers.organization import (
|
||||
Tenant,
|
||||
TenantModelSerializer
|
||||
)
|
||||
|
||||
User = django.contrib.auth.get_user_model()
|
||||
|
||||
|
||||
|
||||
class OrganizationValidationAPI(
|
||||
TestCase,
|
||||
):
|
||||
|
||||
model = Tenant
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(self):
|
||||
"""Setup Test
|
||||
|
||||
1. Create an org
|
||||
2. Create an item
|
||||
"""
|
||||
|
||||
self.user = User.objects.create(username = 'org_user', password='random password')
|
||||
|
||||
self.valid_data = {
|
||||
'name': 'valid_org_data',
|
||||
'manager': self.user.id
|
||||
}
|
||||
|
||||
self.item = self.model.objects.create(
|
||||
name = 'random title',
|
||||
)
|
||||
|
||||
|
||||
|
||||
def test_serializer_valid_data(self):
|
||||
"""Serializer Validation Check
|
||||
|
||||
Ensure that if creating and no name is provided a validation error occurs
|
||||
"""
|
||||
|
||||
serializer = TenantModelSerializer(
|
||||
data = self.valid_data
|
||||
)
|
||||
|
||||
assert serializer.is_valid(raise_exception = True)
|
||||
|
||||
|
||||
|
||||
def test_serializer_validation_no_name(self):
|
||||
"""Serializer Validation Check
|
||||
|
||||
Ensure that if creating and no name is provided a validation error occurs
|
||||
"""
|
||||
|
||||
data = self.valid_data.copy()
|
||||
|
||||
del data['name']
|
||||
|
||||
with pytest.raises(ValidationError) as err:
|
||||
|
||||
serializer = TenantModelSerializer(
|
||||
data = data
|
||||
)
|
||||
|
||||
serializer.is_valid(raise_exception = True)
|
||||
|
||||
assert err.value.get_codes()['name'][0] == 'required'
|
||||
|
||||
|
||||
|
||||
def test_serializer_validation_manager_optional(self):
|
||||
"""Serializer Validation Check
|
||||
|
||||
Ensure that if creating and no name is provided a validation error occurs
|
||||
"""
|
||||
|
||||
data = self.valid_data.copy()
|
||||
|
||||
del data['manager']
|
||||
|
||||
serializer = TenantModelSerializer(
|
||||
data = data
|
||||
)
|
||||
|
||||
assert serializer.is_valid(raise_exception = True)
|
25
app/access/tests/functional/tenant/conftest.py
Normal file
25
app/access/tests/functional/tenant/conftest.py
Normal file
@ -0,0 +1,25 @@
|
||||
import pytest
|
||||
|
||||
|
||||
|
||||
@pytest.fixture( scope = 'class')
|
||||
def model(model_tenant):
|
||||
|
||||
yield model_tenant
|
||||
|
||||
|
||||
@pytest.fixture( scope = 'class', autouse = True)
|
||||
def model_kwargs(request, kwargs_tenant):
|
||||
|
||||
request.cls.kwargs_create_item = kwargs_tenant.copy()
|
||||
|
||||
yield kwargs_tenant.copy()
|
||||
|
||||
if hasattr(request.cls, 'kwargs_create_item'):
|
||||
del request.cls.kwargs_create_item
|
||||
|
||||
|
||||
@pytest.fixture( scope = 'class')
|
||||
def model_serializer(serializer_tenant):
|
||||
|
||||
yield serializer_tenant
|
@ -0,0 +1,117 @@
|
||||
import pytest
|
||||
|
||||
from rest_framework.relations import Hyperlink
|
||||
|
||||
from django.db import models
|
||||
from django.test import Client
|
||||
|
||||
from api.tests.functional.test_functional_api_fields import (
|
||||
APIFieldsInheritedCases,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@pytest.mark.model_tenant
|
||||
class TenantAPITestCases(
|
||||
APIFieldsInheritedCases,
|
||||
):
|
||||
|
||||
@pytest.fixture( scope = 'class')
|
||||
def make_request(self, django_db_blocker,
|
||||
request, organization_one,
|
||||
api_request_permissions,
|
||||
):
|
||||
|
||||
client = Client()
|
||||
|
||||
with django_db_blocker.unblock():
|
||||
|
||||
organization_one.manager = api_request_permissions['user']['view']
|
||||
organization_one.model_notes = 'sad'
|
||||
organization_one.save()
|
||||
|
||||
client.force_login( api_request_permissions['user']['view'] )
|
||||
response = client.get(
|
||||
organization_one.get_url()
|
||||
)
|
||||
|
||||
request.cls.api_data = response.data
|
||||
|
||||
|
||||
|
||||
item_two = getattr(request.cls, 'item_two', None)
|
||||
|
||||
if item_two:
|
||||
|
||||
response_two = client.get( self.item_two.get_url() )
|
||||
|
||||
request.cls.api_data_two = response_two.data
|
||||
|
||||
else:
|
||||
|
||||
request.cls.api_data_two = {}
|
||||
|
||||
|
||||
yield
|
||||
|
||||
with django_db_blocker.unblock():
|
||||
|
||||
organization_one.manager = None
|
||||
organization_one.model_notes = None
|
||||
organization_one.save()
|
||||
|
||||
|
||||
@property
|
||||
def parameterized_api_fields(self):
|
||||
|
||||
return {
|
||||
'_urls.notes': {
|
||||
'expected': models.NOT_PROVIDED
|
||||
},
|
||||
'organization': {
|
||||
'expected': models.NOT_PROVIDED
|
||||
},
|
||||
'organization.id': {
|
||||
'expected': models.NOT_PROVIDED
|
||||
},
|
||||
'organization.display_name': {
|
||||
'expected': models.NOT_PROVIDED
|
||||
},
|
||||
'organization.url': {
|
||||
'expected': models.NOT_PROVIDED
|
||||
},
|
||||
'name': {
|
||||
'expected': str
|
||||
},
|
||||
'manager': {
|
||||
'expected': dict
|
||||
},
|
||||
'manager.id': {
|
||||
'expected': int
|
||||
},
|
||||
'manager.display_name': {
|
||||
'expected': str
|
||||
},
|
||||
'manager.url': {
|
||||
'expected': Hyperlink
|
||||
},
|
||||
'modified': {
|
||||
'expected': str
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class TenantAPIInheritedCases(
|
||||
TenantAPITestCases,
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@pytest.mark.module_access
|
||||
class TenantAPIPyTest(
|
||||
TenantAPITestCases,
|
||||
):
|
||||
|
||||
pass
|
@ -0,0 +1,28 @@
|
||||
import pytest
|
||||
|
||||
from core.tests.functional.centurion_abstract.test_functional_centurion_abstract_model import (
|
||||
CenturionAbstractModelInheritedCases
|
||||
)
|
||||
|
||||
|
||||
|
||||
@pytest.mark.model_tenant
|
||||
class TenantModelTestCases(
|
||||
CenturionAbstractModelInheritedCases
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class TenantModelInheritedCases(
|
||||
TenantModelTestCases,
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@pytest.mark.module_access
|
||||
class TenantModelPyTest(
|
||||
TenantModelTestCases,
|
||||
):
|
||||
pass
|
@ -16,6 +16,7 @@ User = django.contrib.auth.get_user_model()
|
||||
|
||||
|
||||
|
||||
@pytest.mark.model_tenant
|
||||
class ViewSetBase:
|
||||
|
||||
model = Organization
|
||||
@ -191,16 +192,7 @@ class ViewSetBase:
|
||||
|
||||
|
||||
|
||||
class OrganizationViewSet(
|
||||
ViewSetBase,
|
||||
SerializersTestCases,
|
||||
TestCase
|
||||
):
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@pytest.mark.module_access
|
||||
class OrganizationMetadata(
|
||||
ViewSetBase,
|
||||
MetadataAttributesFunctional,
|
@ -1,199 +0,0 @@
|
||||
import django
|
||||
import pytest
|
||||
import unittest
|
||||
|
||||
from django.contrib.auth import get_user_model
|
||||
from django.contrib.auth.models import AnonymousUser, Permission
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.shortcuts import reverse
|
||||
from django.test import Client, TestCase
|
||||
|
||||
from rest_framework.relations import Hyperlink
|
||||
|
||||
from access.models.tenant import Tenant as Organization
|
||||
from access.models.team import Team
|
||||
from access.models.team_user import TeamUsers
|
||||
|
||||
|
||||
from api.tests.abstract.api_fields import APICommonFields
|
||||
|
||||
User = django.contrib.auth.get_user_model()
|
||||
|
||||
|
||||
|
||||
class OrganizationAPI(
|
||||
TestCase,
|
||||
APICommonFields
|
||||
):
|
||||
|
||||
model = Organization
|
||||
|
||||
app_namespace = 'v2'
|
||||
|
||||
url_name = '_api_tenant'
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(self):
|
||||
"""Setup Test
|
||||
|
||||
1. Create the object
|
||||
2. create view user
|
||||
3. add user as org manager
|
||||
4. make api request
|
||||
"""
|
||||
|
||||
organization = Organization.objects.create(name='test_org', model_notes='random text')
|
||||
|
||||
self.organization = organization
|
||||
|
||||
|
||||
self.item = organization
|
||||
|
||||
self.url_view_kwargs = {'pk': self.item.id}
|
||||
|
||||
view_permissions = Permission.objects.get(
|
||||
codename = 'view_' + self.model._meta.model_name,
|
||||
content_type = ContentType.objects.get(
|
||||
app_label = self.model._meta.app_label,
|
||||
model = self.model._meta.model_name,
|
||||
)
|
||||
)
|
||||
|
||||
view_team = Team.objects.create(
|
||||
team_name = 'view_team',
|
||||
organization = organization,
|
||||
)
|
||||
|
||||
view_team.permissions.set([view_permissions])
|
||||
|
||||
|
||||
self.view_user = User.objects.create_user(username="test_user_view", password="password")
|
||||
teamuser = TeamUsers.objects.create(
|
||||
team = view_team,
|
||||
user = self.view_user
|
||||
)
|
||||
|
||||
organization.manager = self.view_user
|
||||
|
||||
organization.save()
|
||||
|
||||
|
||||
client = Client()
|
||||
url = reverse(self.app_namespace + ':' + self.url_name + '-detail', kwargs=self.url_view_kwargs)
|
||||
|
||||
|
||||
client.force_login(self.view_user)
|
||||
response = client.get(url)
|
||||
|
||||
self.api_data = response.data
|
||||
|
||||
|
||||
|
||||
def test_api_field_exists_name(self):
|
||||
""" Test for existance of API Field
|
||||
|
||||
name field must exist
|
||||
"""
|
||||
|
||||
assert 'name' in self.api_data
|
||||
|
||||
|
||||
def test_api_field_type_name(self):
|
||||
""" Test for type for API Field
|
||||
|
||||
name field must be str
|
||||
"""
|
||||
|
||||
assert type(self.api_data['name']) is str
|
||||
|
||||
|
||||
|
||||
def test_api_field_exists_manager(self):
|
||||
""" Test for existance of API Field
|
||||
|
||||
manager field must exist
|
||||
"""
|
||||
|
||||
assert 'manager' in self.api_data
|
||||
|
||||
|
||||
def test_api_field_type_manager(self):
|
||||
""" Test for type for API Field
|
||||
|
||||
manager field must be dict
|
||||
"""
|
||||
|
||||
assert type(self.api_data['manager']) is dict
|
||||
|
||||
|
||||
def test_api_field_exists_manager_id(self):
|
||||
""" Test for existance of API Field
|
||||
|
||||
manager.id field must exist
|
||||
"""
|
||||
|
||||
assert 'id' in self.api_data['manager']
|
||||
|
||||
|
||||
def test_api_field_type_manager_id(self):
|
||||
""" Test for type for API Field
|
||||
|
||||
manager.id field must be int
|
||||
"""
|
||||
|
||||
assert type(self.api_data['manager']['id']) is int
|
||||
|
||||
|
||||
def test_api_field_exists_manager_display_name(self):
|
||||
""" Test for existance of API Field
|
||||
|
||||
manager.display_name field must exist
|
||||
"""
|
||||
|
||||
assert 'display_name' in self.api_data['manager']
|
||||
|
||||
|
||||
def test_api_field_type_manager_display_name(self):
|
||||
""" Test for type for API Field
|
||||
|
||||
manager.display_name field must be int
|
||||
"""
|
||||
|
||||
assert type(self.api_data['manager']['display_name']) is str
|
||||
|
||||
|
||||
def test_api_field_exists_manager_url(self):
|
||||
""" Test for existance of API Field
|
||||
|
||||
manager.display_name field must exist
|
||||
"""
|
||||
|
||||
assert 'url' in self.api_data['manager']
|
||||
|
||||
|
||||
def test_api_field_type_manager_url(self):
|
||||
""" Test for type for API Field
|
||||
|
||||
manager.url field must be Hyperlink
|
||||
"""
|
||||
|
||||
assert type(self.api_data['manager']['url']) is Hyperlink
|
||||
|
||||
|
||||
|
||||
def test_api_field_exists_url_teams(self):
|
||||
""" Test for existance of API Field
|
||||
|
||||
_urls.teams field must exist
|
||||
"""
|
||||
|
||||
assert 'teams' in self.api_data['_urls']
|
||||
|
||||
|
||||
def test_api_field_type_url_teams(self):
|
||||
""" Test for type for API Field
|
||||
|
||||
_urls.teams field must be Hyperlink
|
||||
"""
|
||||
|
||||
assert type(self.api_data['_urls']['teams']) is str
|
@ -1,18 +1,94 @@
|
||||
import pytest
|
||||
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
from api.tests.unit.test_unit_serializer import (
|
||||
SerializerTestCases
|
||||
)
|
||||
|
||||
|
||||
class TenantSerializerTestCases(
|
||||
SerializerTestCases
|
||||
):
|
||||
pass
|
||||
from centurion.tests.abstract.mock_view import MockView
|
||||
|
||||
|
||||
|
||||
@pytest.mark.model_tenant
|
||||
class TenantSerializerTestCases(
|
||||
SerializerTestCases
|
||||
):
|
||||
|
||||
@pytest.fixture( scope = 'function' )
|
||||
def created_model(self, django_db_blocker, model, model_kwargs):
|
||||
|
||||
with django_db_blocker.unblock():
|
||||
|
||||
item = model.objects.create( **model_kwargs )
|
||||
|
||||
yield item
|
||||
|
||||
item.delete()
|
||||
|
||||
|
||||
def test_serializer_validation_no_name(self,
|
||||
kwargs_api_create, model, model_serializer, request_user
|
||||
):
|
||||
"""Serializer Validation Check
|
||||
|
||||
Ensure that if creating and no name is provided a validation error occurs
|
||||
"""
|
||||
|
||||
mock_view = MockView(
|
||||
user = request_user,
|
||||
model = model,
|
||||
action = 'create',
|
||||
)
|
||||
|
||||
kwargs = kwargs_api_create.copy()
|
||||
del kwargs['name']
|
||||
|
||||
with pytest.raises(ValidationError) as err:
|
||||
|
||||
serializer = model_serializer['model'](
|
||||
context = {
|
||||
'request': mock_view.request,
|
||||
'view': mock_view,
|
||||
},
|
||||
data = kwargs
|
||||
)
|
||||
|
||||
serializer.is_valid(raise_exception = True)
|
||||
|
||||
assert err.value.get_codes()['name'][0] == 'required'
|
||||
|
||||
|
||||
|
||||
def test_serializer_validation_manager_optional(self,
|
||||
kwargs_api_create, model, model_serializer, request_user
|
||||
):
|
||||
"""Serializer Validation Check
|
||||
|
||||
Ensure that if creating and no name is provided a validation error occurs
|
||||
"""
|
||||
|
||||
mock_view = MockView(
|
||||
user = request_user,
|
||||
model = model,
|
||||
action = 'create',
|
||||
)
|
||||
|
||||
kwargs = kwargs_api_create.copy()
|
||||
del kwargs['manager']
|
||||
|
||||
serializer = model_serializer['model'](
|
||||
context = {
|
||||
'request': mock_view.request,
|
||||
'view': mock_view,
|
||||
},
|
||||
data = kwargs
|
||||
)
|
||||
|
||||
assert serializer.is_valid(raise_exception = True)
|
||||
|
||||
|
||||
|
||||
@pytest.mark.module_access
|
||||
class TenantSerializerPyTest(
|
||||
TenantSerializerTestCases
|
||||
|
@ -34,17 +34,17 @@ router = DefaultRouter(trailing_slash=False)
|
||||
router.register('', access_v2.Index, basename = '_api_v2_access_home')
|
||||
|
||||
router.register(
|
||||
prefix = '(?P<model_name>[company]+)', viewset = entity.ViewSet,
|
||||
prefix = '/(?P<model_name>[company]+)', viewset = entity.ViewSet,
|
||||
feature_flag = '2025-00008',basename = '_api_v2_company'
|
||||
)
|
||||
|
||||
router.register(
|
||||
prefix=f'entity/(?P<model_name>[{entity_type_names}]+)?', viewset = entity.ViewSet,
|
||||
prefix=f'/entity/(?P<model_name>[{entity_type_names}]+)?', viewset = entity.ViewSet,
|
||||
feature_flag = '2025-00002', basename = '_api_entity_sub'
|
||||
)
|
||||
|
||||
router.register(
|
||||
prefix = 'entity', viewset = entity.NoDocsViewSet,
|
||||
prefix = '/entity', viewset = entity.NoDocsViewSet,
|
||||
feature_flag = '2025-00002', basename = '_api_entity'
|
||||
)
|
||||
|
||||
@ -54,7 +54,7 @@ router.register(
|
||||
# )
|
||||
|
||||
router.register(
|
||||
prefix = 'tenant', viewset = organization.ViewSet,
|
||||
prefix = '/tenant', viewset = organization.ViewSet,
|
||||
basename = '_api_tenant'
|
||||
)
|
||||
|
||||
@ -64,7 +64,7 @@ router.register(
|
||||
# )
|
||||
|
||||
router.register(
|
||||
prefix = 'tenant/(?P<organization_id>[0-9]+)/team', viewset = team_v2.ViewSet,
|
||||
prefix = '/tenant/(?P<organization_id>[0-9]+)/team', viewset = team_v2.ViewSet,
|
||||
basename = '_api_v2_organization_team'
|
||||
)
|
||||
|
||||
@ -75,13 +75,13 @@ router.register(
|
||||
# )
|
||||
|
||||
router.register(
|
||||
prefix = 'access/tenant/(?P<organization_id>[0-9]+)/team/(?P<team_id>[0-9]+)/user',
|
||||
prefix = '/access/tenant/(?P<organization_id>[0-9]+)/team/(?P<team_id>[0-9]+)/user',
|
||||
viewset = team_user_v2.ViewSet,
|
||||
basename = '_api_v2_organization_team_user'
|
||||
)
|
||||
|
||||
router.register(
|
||||
prefix = 'role', viewset = role.ViewSet,
|
||||
prefix = '/role', viewset = role.ViewSet,
|
||||
feature_flag = '2025-00003', basename = '_api_role'
|
||||
)
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
# Generated by Django 5.1.10 on 2025-07-10 09:10
|
||||
# Generated by Django 5.1.10 on 2025-08-15 03:21
|
||||
|
||||
import access.models.tenancy_abstract
|
||||
import django.db.models.deletion
|
||||
@ -8,9 +8,9 @@ from django.db import migrations, models
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0019_companyaudithistory_companycenturionmodelnote"),
|
||||
("access", "0011_remove_entitynotes_model_and_more"),
|
||||
("accounting", "0001_initial"),
|
||||
("core", "0033_alter_ticketcommentcategory_parent_and_more"),
|
||||
("core", "0024_centurionaudit_centurionmodelnote_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
@ -115,4 +115,10 @@ class Migration(migrations.Migration):
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name="AssetBaseHistory",
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name="AssetBaseNotes",
|
||||
),
|
||||
]
|
@ -1,19 +0,0 @@
|
||||
# Generated by Django 5.1.10 on 2025-07-10 09:31
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("accounting", "0002_alter_assetbase_id_alter_assetbase_model_notes_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel(
|
||||
name="AssetBaseHistory",
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name="AssetBaseNotes",
|
||||
),
|
||||
]
|
@ -42,7 +42,7 @@ asset_type_names = str(asset_type_names)[:-1]
|
||||
if not asset_type_names:
|
||||
asset_type_names = 'none'
|
||||
|
||||
router.register(f'asset/(?P<model_name>[{asset_type_names}]+)?', asset.ViewSet, feature_flag = '2025-00004', basename='_api_asset_sub')
|
||||
router.register('asset', asset.NoDocsViewSet, feature_flag = '2025-00004', basename='_api_asset')
|
||||
router.register(f'/asset/(?P<model_name>[{asset_type_names}]+)?', asset.ViewSet, feature_flag = '2025-00004', basename='_api_asset_sub')
|
||||
router.register('/asset', asset.NoDocsViewSet, feature_flag = '2025-00004', basename='_api_asset')
|
||||
|
||||
urlpatterns = router.urls
|
||||
|
@ -1,5 +1,10 @@
|
||||
|
||||
from django.core.exceptions import (
|
||||
ValidationError as DjangoValidationError,
|
||||
)
|
||||
from rest_framework import serializers
|
||||
from rest_framework.exceptions import (
|
||||
ValidationError
|
||||
)
|
||||
from rest_framework.reverse import reverse
|
||||
|
||||
from access.serializers.organization import Tenant
|
||||
@ -44,15 +49,16 @@ class CommonModelSerializer(CommonBaseSerializer):
|
||||
_**Note:** This serializer is not inherited by the organization Serializer_
|
||||
_`access.serializers.organization`, this is by design_
|
||||
|
||||
This serializer is included within ALL model (Tenancy Model) serilaizers and is intended to be used
|
||||
to add objects that ALL model serializers will require.
|
||||
This serializer is included within ALL model (Tenancy Model) serilaizers
|
||||
and is intended to be used to add objects that ALL model serializers will
|
||||
require.
|
||||
|
||||
Args:
|
||||
CommonBaseSerializer (Class): Common base serializer
|
||||
"""
|
||||
|
||||
model_notes = centurion_field.MarkdownField( required = False )
|
||||
|
||||
|
||||
organization = OrganizationField(required = False)
|
||||
|
||||
|
||||
@ -169,3 +175,32 @@ class CommonModelSerializer(CommonBaseSerializer):
|
||||
)
|
||||
|
||||
return get_url
|
||||
|
||||
|
||||
def is_valid(self, *, raise_exception=False):
|
||||
is_valid = False
|
||||
|
||||
try:
|
||||
is_valid = super().is_valid(raise_exception=raise_exception)
|
||||
except DjangoValidationError as ex:
|
||||
|
||||
if raise_exception:
|
||||
raise ValidationError( serializers.as_serializer_error(ex ) )
|
||||
|
||||
|
||||
return is_valid
|
||||
|
||||
|
||||
def save(self, **kwargs):
|
||||
save = None
|
||||
|
||||
try:
|
||||
|
||||
save = super().save( **kwargs )
|
||||
|
||||
except DjangoValidationError as ex:
|
||||
|
||||
raise ValidationError( serializers.as_serializer_error(ex ) )
|
||||
|
||||
|
||||
return save
|
||||
|
25
app/api/tests/functional/auth_token/conftest.py
Normal file
25
app/api/tests/functional/auth_token/conftest.py
Normal file
@ -0,0 +1,25 @@
|
||||
import pytest
|
||||
|
||||
|
||||
|
||||
@pytest.fixture( scope = 'class')
|
||||
def model(model_authtoken):
|
||||
|
||||
yield model_authtoken
|
||||
|
||||
|
||||
@pytest.fixture( scope = 'class', autouse = True)
|
||||
def model_kwargs(request, kwargs_authtoken):
|
||||
|
||||
request.cls.kwargs_create_item = kwargs_authtoken.copy()
|
||||
|
||||
yield kwargs_authtoken.copy()
|
||||
|
||||
if hasattr(request.cls, 'kwargs_create_item'):
|
||||
del request.cls.kwargs_create_item
|
||||
|
||||
|
||||
@pytest.fixture( scope = 'class')
|
||||
def model_serializer(serializer_authtoken):
|
||||
|
||||
yield serializer_authtoken
|
@ -0,0 +1,113 @@
|
||||
import pytest
|
||||
|
||||
from django.db import models
|
||||
|
||||
from rest_framework.relations import Hyperlink
|
||||
|
||||
from api.tests.functional.test_functional_api_fields import (
|
||||
APIFieldsInheritedCases,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@pytest.mark.model_authtoken
|
||||
class AuthTokenAPITestCases(
|
||||
APIFieldsInheritedCases,
|
||||
):
|
||||
|
||||
|
||||
@pytest.fixture( scope = 'class')
|
||||
def create_model(self, request, django_db_blocker,
|
||||
model, model_kwargs, api_request_permissions,
|
||||
):
|
||||
|
||||
item = None
|
||||
|
||||
with django_db_blocker.unblock():
|
||||
|
||||
kwargs = model_kwargs.copy()
|
||||
kwargs['user'] = api_request_permissions['user']['view']
|
||||
|
||||
|
||||
item = model.objects.create(
|
||||
**kwargs
|
||||
)
|
||||
|
||||
request.cls.item = item
|
||||
|
||||
yield item
|
||||
|
||||
with django_db_blocker.unblock():
|
||||
|
||||
item.delete()
|
||||
|
||||
|
||||
@property
|
||||
def parameterized_api_fields(self):
|
||||
|
||||
return {
|
||||
'_urls.notes': {
|
||||
'expected': models.NOT_PROVIDED
|
||||
},
|
||||
'model_notes': {
|
||||
'expected': models.NOT_PROVIDED
|
||||
},
|
||||
'id': {
|
||||
'expected': int
|
||||
},
|
||||
'note': {
|
||||
'expected': str
|
||||
},
|
||||
'token': { # Must not be in fields
|
||||
'expected': models.NOT_PROVIDED
|
||||
},
|
||||
'user': {
|
||||
'expected': int
|
||||
},
|
||||
'user.id': { # Must not be in fields as object belongs to user requesting
|
||||
'expected': models.NOT_PROVIDED
|
||||
},
|
||||
'user.display_name': { # Must not be in fields as object belongs to user requesting
|
||||
'expected': models.NOT_PROVIDED
|
||||
},
|
||||
'user.url': { # Must not be in fields as object belongs to user requesting
|
||||
'expected': models.NOT_PROVIDED
|
||||
},
|
||||
'organization': { # Not a tenancy model
|
||||
'expected': models.NOT_PROVIDED
|
||||
},
|
||||
'organization.id': { # Not a tenancy model
|
||||
'expected': models.NOT_PROVIDED
|
||||
},
|
||||
'organization.display_name': { # Not a tenancy model
|
||||
'expected': models.NOT_PROVIDED
|
||||
},
|
||||
'organization.url': { # Not a tenancy model
|
||||
'expected': models.NOT_PROVIDED
|
||||
},
|
||||
'expires': {
|
||||
'expected': str
|
||||
},
|
||||
'created': {
|
||||
'expected': str
|
||||
},
|
||||
'modified': {
|
||||
'expected': str
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class AuthTokenAPIInheritedCases(
|
||||
AuthTokenAPITestCases,
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@pytest.mark.module_api
|
||||
class AuthTokenAPIPyTest(
|
||||
AuthTokenAPITestCases,
|
||||
):
|
||||
|
||||
pass
|
@ -0,0 +1,223 @@
|
||||
import django
|
||||
import pytest
|
||||
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.test import TestCase
|
||||
|
||||
from access.models.tenant import Tenant as Organization
|
||||
from access.models.team import Team
|
||||
from access.models.team_user import TeamUsers
|
||||
|
||||
from api.models.tokens import AuthToken
|
||||
|
||||
from api.tests.abstract.test_metadata_functional import (
|
||||
MetadataAttributesFunctionalEndpoint,
|
||||
MetadataAttributesFunctionalBase,
|
||||
)
|
||||
|
||||
User = django.contrib.auth.get_user_model()
|
||||
|
||||
|
||||
|
||||
@pytest.mark.model_authtoken
|
||||
class ViewSetBase:
|
||||
|
||||
model = AuthToken
|
||||
|
||||
app_namespace = 'v2'
|
||||
|
||||
url_name = '_api_authtoken'
|
||||
|
||||
change_data = {'device_model_is_global': True}
|
||||
|
||||
delete_data = {}
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(self):
|
||||
"""Setup Test
|
||||
|
||||
1. Create an organization for user and item
|
||||
. create an organization that is different to item
|
||||
2. Create a team
|
||||
3. create teams with each permission: view, add, change, delete
|
||||
4. create a user per team
|
||||
"""
|
||||
|
||||
organization = Organization.objects.create(name='test_org')
|
||||
|
||||
self.organization = organization
|
||||
|
||||
different_organization = Organization.objects.create(name='test_different_organization')
|
||||
|
||||
self.different_organization = different_organization
|
||||
|
||||
|
||||
view_permissions = Permission.objects.get(
|
||||
codename = 'view_' + self.model._meta.model_name,
|
||||
content_type = ContentType.objects.get(
|
||||
app_label = self.model._meta.app_label,
|
||||
model = self.model._meta.model_name,
|
||||
)
|
||||
)
|
||||
|
||||
view_team = Team.objects.create(
|
||||
team_name = 'view_team',
|
||||
organization = organization,
|
||||
)
|
||||
|
||||
view_team.permissions.set([view_permissions])
|
||||
|
||||
|
||||
|
||||
add_permissions = Permission.objects.get(
|
||||
codename = 'add_' + self.model._meta.model_name,
|
||||
content_type = ContentType.objects.get(
|
||||
app_label = self.model._meta.app_label,
|
||||
model = self.model._meta.model_name,
|
||||
)
|
||||
)
|
||||
|
||||
add_team = Team.objects.create(
|
||||
team_name = 'add_team',
|
||||
organization = organization,
|
||||
)
|
||||
|
||||
add_team.permissions.set([add_permissions])
|
||||
|
||||
|
||||
|
||||
change_permissions = Permission.objects.get(
|
||||
codename = 'change_' + self.model._meta.model_name,
|
||||
content_type = ContentType.objects.get(
|
||||
app_label = self.model._meta.app_label,
|
||||
model = self.model._meta.model_name,
|
||||
)
|
||||
)
|
||||
|
||||
change_team = Team.objects.create(
|
||||
team_name = 'change_team',
|
||||
organization = organization,
|
||||
)
|
||||
|
||||
change_team.permissions.set([change_permissions])
|
||||
|
||||
|
||||
|
||||
delete_permissions = Permission.objects.get(
|
||||
codename = 'delete_' + self.model._meta.model_name,
|
||||
content_type = ContentType.objects.get(
|
||||
app_label = self.model._meta.app_label,
|
||||
model = self.model._meta.model_name,
|
||||
)
|
||||
)
|
||||
|
||||
delete_team = Team.objects.create(
|
||||
team_name = 'delete_team',
|
||||
organization = organization,
|
||||
)
|
||||
|
||||
delete_team.permissions.set([delete_permissions])
|
||||
|
||||
|
||||
self.no_permissions_user = User.objects.create_user(username="test_no_permissions", password="password")
|
||||
|
||||
|
||||
self.add_user = User.objects.create_user(username="test_user_add", password="password")
|
||||
teamuser = TeamUsers.objects.create(
|
||||
team = add_team,
|
||||
user = self.add_user
|
||||
)
|
||||
|
||||
self.change_user = User.objects.create_user(username="test_user_change", password="password")
|
||||
teamuser = TeamUsers.objects.create(
|
||||
team = change_team,
|
||||
user = self.change_user
|
||||
)
|
||||
|
||||
self.delete_user = User.objects.create_user(username="test_user_delete", password="password")
|
||||
teamuser = TeamUsers.objects.create(
|
||||
team = delete_team,
|
||||
user = self.delete_user
|
||||
)
|
||||
|
||||
self.view_user = User.objects.create_user(username="test_user_view", password="password")
|
||||
teamuser = TeamUsers.objects.create(
|
||||
team = view_team,
|
||||
user = self.view_user
|
||||
)
|
||||
|
||||
self.item = self.model.objects.create(
|
||||
note = 'a note',
|
||||
token = self.model().generate,
|
||||
user = self.view_user,
|
||||
expires = '2025-02-25T23:14Z'
|
||||
)
|
||||
|
||||
self.item_delete = self.model.objects.create(
|
||||
note = 'a note',
|
||||
token = self.model().generate,
|
||||
user = self.delete_user,
|
||||
expires = '2025-02-25T23:14Z'
|
||||
)
|
||||
|
||||
# self.item.default_organization = self.organization
|
||||
|
||||
# self.item.save()
|
||||
|
||||
|
||||
self.url_view_kwargs = {
|
||||
'model_id': self.view_user.id,
|
||||
'pk': self.item.id,
|
||||
}
|
||||
|
||||
self.url_kwargs = {
|
||||
'model_id': self.view_user.id,
|
||||
}
|
||||
|
||||
self.add_data = {
|
||||
'note': 'a note',
|
||||
'token': self.model().generate,
|
||||
'expires': '2025-02-26T23:14Z'
|
||||
}
|
||||
|
||||
|
||||
|
||||
self.different_organization_user = User.objects.create_user(username="test_different_organization_user", password="password")
|
||||
|
||||
|
||||
different_organization_team = Team.objects.create(
|
||||
team_name = 'different_organization_team',
|
||||
organization = different_organization,
|
||||
)
|
||||
|
||||
different_organization_team.permissions.set([
|
||||
view_permissions,
|
||||
add_permissions,
|
||||
change_permissions,
|
||||
delete_permissions,
|
||||
])
|
||||
|
||||
TeamUsers.objects.create(
|
||||
team = different_organization_team,
|
||||
user = self.different_organization_user
|
||||
)
|
||||
|
||||
|
||||
|
||||
@pytest.mark.module_api
|
||||
class Metadata(
|
||||
ViewSetBase,
|
||||
MetadataAttributesFunctionalEndpoint,
|
||||
MetadataAttributesFunctionalBase,
|
||||
TestCase
|
||||
):
|
||||
|
||||
viewset_type = 'detail'
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(self):
|
||||
|
||||
super().setUpTestData()
|
||||
|
||||
self.url_kwargs = self.url_view_kwargs
|
@ -0,0 +1,28 @@
|
||||
import pytest
|
||||
|
||||
from core.tests.functional.centurion_abstract.test_functional_centurion_abstract_model import (
|
||||
CenturionAbstractModelInheritedCases
|
||||
)
|
||||
|
||||
|
||||
|
||||
@pytest.mark.model_authtoken
|
||||
class AuthTokenModelTestCases(
|
||||
CenturionAbstractModelInheritedCases
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class AuthTokenModelInheritedCases(
|
||||
AuthTokenModelTestCases,
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@pytest.mark.module_api
|
||||
class AuthTokenModelPyTest(
|
||||
AuthTokenModelTestCases,
|
||||
):
|
||||
pass
|
@ -1,162 +0,0 @@
|
||||
import pytest
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
from rest_framework.exceptions import ValidationError, PermissionDenied
|
||||
|
||||
from access.models.tenant import Tenant as Organization
|
||||
|
||||
from api.serializers.auth_token import AuthToken, AuthTokenModelSerializer
|
||||
|
||||
from centurion.tests.abstract.mock_view import MockView, User
|
||||
|
||||
|
||||
|
||||
@pytest.mark.model_authtoken
|
||||
@pytest.mark.module_api
|
||||
class ValidationAPI(
|
||||
TestCase,
|
||||
):
|
||||
|
||||
model = AuthToken
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(self):
|
||||
"""Setup Test
|
||||
|
||||
1. Create an org
|
||||
2. Create an item
|
||||
"""
|
||||
|
||||
organization = Organization.objects.create(name='test_org')
|
||||
|
||||
self.organization = organization
|
||||
|
||||
self.user = User.objects.create_user(username="test_user_view", password="password")
|
||||
|
||||
self.valid_data = {
|
||||
'note': 'a note',
|
||||
'token': self.model().generate,
|
||||
'user': self.user.id,
|
||||
'expires': '2025-02-26T00:09Z'
|
||||
}
|
||||
|
||||
self.mock_view = MockView( user = self.user )
|
||||
|
||||
self.mock_view.kwargs = {
|
||||
'model_id': self.user.id
|
||||
}
|
||||
|
||||
self.item = self.model.objects.create(
|
||||
note = 'object note',
|
||||
token = self.model().generate,
|
||||
user = self.user,
|
||||
expires = '2025-02-26T00:07Z'
|
||||
)
|
||||
|
||||
|
||||
|
||||
def test_serializer_validation_valid_data(self):
|
||||
"""Serializer Validation Check
|
||||
|
||||
Ensure that if creating with valid data, the object is created
|
||||
"""
|
||||
|
||||
serializer = AuthTokenModelSerializer(
|
||||
context = {
|
||||
'request': self.mock_view.request,
|
||||
'view': self.mock_view,
|
||||
},
|
||||
data = self.valid_data
|
||||
)
|
||||
|
||||
assert serializer.is_valid(raise_exception = True)
|
||||
|
||||
|
||||
|
||||
def test_serializer_validation_valid_data_different_user(self):
|
||||
"""Serializer Validation Check
|
||||
|
||||
Ensure that if adding the same manufacturer
|
||||
it raises a validation error
|
||||
"""
|
||||
|
||||
class MockUser:
|
||||
|
||||
id = 99
|
||||
|
||||
mock_view = MockView( user = self.user )
|
||||
|
||||
mock_view.request.user = MockUser()
|
||||
|
||||
mock_view.kwargs = {
|
||||
'model_id': self.user.id
|
||||
}
|
||||
|
||||
with pytest.raises(PermissionDenied) as err:
|
||||
|
||||
serializer = AuthTokenModelSerializer(
|
||||
context = {
|
||||
'request': mock_view.request,
|
||||
'view': mock_view,
|
||||
},
|
||||
data = self.valid_data
|
||||
)
|
||||
|
||||
serializer.is_valid(raise_exception = True)
|
||||
|
||||
assert err.value.get_codes() == 'permission_denied'
|
||||
|
||||
|
||||
|
||||
def test_serializer_validation_valid_data_token_not_sha256_same_length(self):
|
||||
"""Serializer Validation Check
|
||||
|
||||
Ensure that if adding the same manufacturer
|
||||
it raises a validation error
|
||||
"""
|
||||
|
||||
valid_data = self.valid_data.copy()
|
||||
|
||||
valid_data['token'] = str(valid_data['token'])[:-5] + 'qwert'
|
||||
|
||||
with pytest.raises(ValidationError) as err:
|
||||
|
||||
serializer = AuthTokenModelSerializer(
|
||||
context = {
|
||||
'request': self.mock_view.request,
|
||||
'view': self.mock_view,
|
||||
},
|
||||
data = valid_data
|
||||
)
|
||||
|
||||
serializer.is_valid(raise_exception = True)
|
||||
|
||||
assert err.value.get_codes()['token'][0] == 'token_not_sha256'
|
||||
|
||||
|
||||
|
||||
def test_serializer_validation_valid_data_token_not_sha256_wrong_length(self):
|
||||
"""Serializer Validation Check
|
||||
|
||||
Ensure that if adding the same manufacturer
|
||||
it raises a validation error
|
||||
"""
|
||||
|
||||
valid_data = self.valid_data.copy()
|
||||
|
||||
valid_data['token'] = str(valid_data['token'])[:-5] + 'qwer'
|
||||
|
||||
with pytest.raises(ValidationError) as err:
|
||||
|
||||
serializer = AuthTokenModelSerializer(
|
||||
context = {
|
||||
'request': self.mock_view.request,
|
||||
'view': self.mock_view,
|
||||
},
|
||||
data = valid_data
|
||||
)
|
||||
|
||||
serializer.is_valid(raise_exception = True)
|
||||
|
||||
assert err.value.get_codes()['token'][0] == 'token_not_sha256'
|
@ -1,388 +0,0 @@
|
||||
import django
|
||||
import pytest
|
||||
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.shortcuts import reverse
|
||||
from django.test import Client, TestCase
|
||||
|
||||
from access.models.tenant import Tenant as Organization
|
||||
from access.models.team import Team
|
||||
from access.models.team_user import TeamUsers
|
||||
|
||||
from api.models.tokens import AuthToken
|
||||
from api.tests.abstract.api_permissions_viewset import (
|
||||
APIPermissionAdd,
|
||||
APIPermissionDelete,
|
||||
APIPermissionView,
|
||||
)
|
||||
from api.tests.abstract.api_serializer_viewset import (
|
||||
SerializerAdd,
|
||||
SerializerDelete,
|
||||
SerializerView,
|
||||
)
|
||||
from api.tests.abstract.test_metadata_functional import (
|
||||
MetadataAttributesFunctionalEndpoint,
|
||||
MetadataAttributesFunctionalBase,
|
||||
)
|
||||
|
||||
User = django.contrib.auth.get_user_model()
|
||||
|
||||
|
||||
|
||||
@pytest.mark.model_authtoken
|
||||
@pytest.mark.module_api
|
||||
class ViewSetBase:
|
||||
|
||||
model = AuthToken
|
||||
|
||||
app_namespace = 'v2'
|
||||
|
||||
url_name = '_api_authtoken'
|
||||
|
||||
change_data = {'device_model_is_global': True}
|
||||
|
||||
delete_data = {}
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(self):
|
||||
"""Setup Test
|
||||
|
||||
1. Create an organization for user and item
|
||||
. create an organization that is different to item
|
||||
2. Create a team
|
||||
3. create teams with each permission: view, add, change, delete
|
||||
4. create a user per team
|
||||
"""
|
||||
|
||||
organization = Organization.objects.create(name='test_org')
|
||||
|
||||
self.organization = organization
|
||||
|
||||
different_organization = Organization.objects.create(name='test_different_organization')
|
||||
|
||||
self.different_organization = different_organization
|
||||
|
||||
|
||||
view_permissions = Permission.objects.get(
|
||||
codename = 'view_' + self.model._meta.model_name,
|
||||
content_type = ContentType.objects.get(
|
||||
app_label = self.model._meta.app_label,
|
||||
model = self.model._meta.model_name,
|
||||
)
|
||||
)
|
||||
|
||||
view_team = Team.objects.create(
|
||||
team_name = 'view_team',
|
||||
organization = organization,
|
||||
)
|
||||
|
||||
view_team.permissions.set([view_permissions])
|
||||
|
||||
|
||||
|
||||
add_permissions = Permission.objects.get(
|
||||
codename = 'add_' + self.model._meta.model_name,
|
||||
content_type = ContentType.objects.get(
|
||||
app_label = self.model._meta.app_label,
|
||||
model = self.model._meta.model_name,
|
||||
)
|
||||
)
|
||||
|
||||
add_team = Team.objects.create(
|
||||
team_name = 'add_team',
|
||||
organization = organization,
|
||||
)
|
||||
|
||||
add_team.permissions.set([add_permissions])
|
||||
|
||||
|
||||
|
||||
change_permissions = Permission.objects.get(
|
||||
codename = 'change_' + self.model._meta.model_name,
|
||||
content_type = ContentType.objects.get(
|
||||
app_label = self.model._meta.app_label,
|
||||
model = self.model._meta.model_name,
|
||||
)
|
||||
)
|
||||
|
||||
change_team = Team.objects.create(
|
||||
team_name = 'change_team',
|
||||
organization = organization,
|
||||
)
|
||||
|
||||
change_team.permissions.set([change_permissions])
|
||||
|
||||
|
||||
|
||||
delete_permissions = Permission.objects.get(
|
||||
codename = 'delete_' + self.model._meta.model_name,
|
||||
content_type = ContentType.objects.get(
|
||||
app_label = self.model._meta.app_label,
|
||||
model = self.model._meta.model_name,
|
||||
)
|
||||
)
|
||||
|
||||
delete_team = Team.objects.create(
|
||||
team_name = 'delete_team',
|
||||
organization = organization,
|
||||
)
|
||||
|
||||
delete_team.permissions.set([delete_permissions])
|
||||
|
||||
|
||||
self.no_permissions_user = User.objects.create_user(username="test_no_permissions", password="password")
|
||||
|
||||
|
||||
self.add_user = User.objects.create_user(username="test_user_add", password="password")
|
||||
teamuser = TeamUsers.objects.create(
|
||||
team = add_team,
|
||||
user = self.add_user
|
||||
)
|
||||
|
||||
self.change_user = User.objects.create_user(username="test_user_change", password="password")
|
||||
teamuser = TeamUsers.objects.create(
|
||||
team = change_team,
|
||||
user = self.change_user
|
||||
)
|
||||
|
||||
self.delete_user = User.objects.create_user(username="test_user_delete", password="password")
|
||||
teamuser = TeamUsers.objects.create(
|
||||
team = delete_team,
|
||||
user = self.delete_user
|
||||
)
|
||||
|
||||
self.view_user = User.objects.create_user(username="test_user_view", password="password")
|
||||
teamuser = TeamUsers.objects.create(
|
||||
team = view_team,
|
||||
user = self.view_user
|
||||
)
|
||||
|
||||
self.item = self.model.objects.create(
|
||||
note = 'a note',
|
||||
token = self.model().generate,
|
||||
user = self.view_user,
|
||||
expires = '2025-02-25T23:14Z'
|
||||
)
|
||||
|
||||
self.item_delete = self.model.objects.create(
|
||||
note = 'a note',
|
||||
token = self.model().generate,
|
||||
user = self.delete_user,
|
||||
expires = '2025-02-25T23:14Z'
|
||||
)
|
||||
|
||||
# self.item.default_organization = self.organization
|
||||
|
||||
# self.item.save()
|
||||
|
||||
|
||||
self.url_view_kwargs = {
|
||||
'model_id': self.view_user.id,
|
||||
'pk': self.item.id,
|
||||
}
|
||||
|
||||
self.url_kwargs = {
|
||||
'model_id': self.view_user.id,
|
||||
}
|
||||
|
||||
self.add_data = {
|
||||
'note': 'a note',
|
||||
'token': self.model().generate,
|
||||
'expires': '2025-02-26T23:14Z'
|
||||
}
|
||||
|
||||
|
||||
|
||||
self.different_organization_user = User.objects.create_user(username="test_different_organization_user", password="password")
|
||||
|
||||
|
||||
different_organization_team = Team.objects.create(
|
||||
team_name = 'different_organization_team',
|
||||
organization = different_organization,
|
||||
)
|
||||
|
||||
different_organization_team.permissions.set([
|
||||
view_permissions,
|
||||
add_permissions,
|
||||
change_permissions,
|
||||
delete_permissions,
|
||||
])
|
||||
|
||||
TeamUsers.objects.create(
|
||||
team = different_organization_team,
|
||||
user = self.different_organization_user
|
||||
)
|
||||
|
||||
|
||||
|
||||
class PermissionsAPI(
|
||||
ViewSetBase,
|
||||
APIPermissionAdd,
|
||||
APIPermissionDelete,
|
||||
APIPermissionView,
|
||||
TestCase,
|
||||
):
|
||||
|
||||
|
||||
def test_returned_data_from_user_and_global_organizations_only(self):
|
||||
"""Check items returned
|
||||
|
||||
This test case is a over-ride of a test case with the same name.
|
||||
This model is not a tenancy model making this test not-applicable.
|
||||
|
||||
Items returned from the query Must be from the users organization and
|
||||
global ONLY!
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
|
||||
def test_add_has_permission(self):
|
||||
""" Check correct permission for add
|
||||
|
||||
Attempt to add as user with permission
|
||||
"""
|
||||
|
||||
url_kwargs = self.url_kwargs.copy()
|
||||
|
||||
url_kwargs['model_id'] = self.add_user.id
|
||||
|
||||
|
||||
client = Client()
|
||||
if self.url_kwargs:
|
||||
|
||||
url = reverse(self.app_namespace + ':' + self.url_name + '-list', kwargs = url_kwargs)
|
||||
|
||||
else:
|
||||
|
||||
url = reverse(self.app_namespace + ':' + self.url_name + '-list')
|
||||
|
||||
|
||||
client.force_login(self.add_user)
|
||||
response = client.post(url, data=self.add_data)
|
||||
|
||||
assert response.status_code == 201
|
||||
|
||||
|
||||
def test_add_permission_view_denied(self):
|
||||
""" Check correct permission for add
|
||||
|
||||
Attempt to add a user with view permission
|
||||
"""
|
||||
|
||||
url_kwargs = self.url_kwargs.copy()
|
||||
|
||||
url_kwargs['model_id'] = self.add_user.id
|
||||
|
||||
client = Client()
|
||||
if self.url_kwargs:
|
||||
|
||||
url = reverse(self.app_namespace + ':' + self.url_name + '-list', kwargs = url_kwargs)
|
||||
|
||||
else:
|
||||
|
||||
url = reverse(self.app_namespace + ':' + self.url_name + '-list')
|
||||
|
||||
|
||||
client.force_login(self.view_user)
|
||||
response = client.post(url, data=self.add_data)
|
||||
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
|
||||
def test_delete_has_permission(self):
|
||||
""" Check correct permission for delete
|
||||
|
||||
Delete item as user with delete permission
|
||||
"""
|
||||
|
||||
url_view_kwargs = self.url_view_kwargs.copy()
|
||||
|
||||
url_view_kwargs['model_id'] = self.delete_user.id
|
||||
url_view_kwargs['pk'] = self.item_delete.id
|
||||
|
||||
client = Client()
|
||||
url = reverse(self.app_namespace + ':' + self.url_name + '-detail', kwargs=url_view_kwargs)
|
||||
|
||||
|
||||
client.force_login(self.delete_user)
|
||||
response = client.delete(url, data=self.delete_data)
|
||||
|
||||
assert response.status_code == 204
|
||||
|
||||
|
||||
def test_delete_permission_view_denied(self):
|
||||
""" Check correct permission for delete
|
||||
|
||||
Attempt to delete as user with veiw permission only
|
||||
"""
|
||||
|
||||
url_view_kwargs = self.url_view_kwargs.copy()
|
||||
|
||||
url_view_kwargs['model_id'] = self.delete_user.id
|
||||
url_view_kwargs['pk'] = self.item_delete.id
|
||||
|
||||
client = Client()
|
||||
url = reverse(self.app_namespace + ':' + self.url_name + '-detail', kwargs=url_view_kwargs)
|
||||
|
||||
|
||||
client.force_login(self.view_user)
|
||||
response = client.delete(url, data=self.delete_data)
|
||||
|
||||
assert response.status_code == 403
|
||||
|
||||
|
||||
|
||||
def test_returned_results_only_user_orgs(self):
|
||||
"""Test not required
|
||||
|
||||
this test is not required as this model is not a tenancy model
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
||||
def test_view_no_permission_denied(self):
|
||||
""" Check correct permission for view
|
||||
|
||||
This test case is a duplicate of a test case with the same name.
|
||||
This test is not required for this model as there are no permissions
|
||||
assosiated with accessing this model.
|
||||
|
||||
Attempt to view with user missing permission
|
||||
"""
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class ViewSet(
|
||||
ViewSetBase,
|
||||
SerializerAdd,
|
||||
SerializerDelete,
|
||||
SerializerView,
|
||||
TestCase,
|
||||
):
|
||||
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class Metadata(
|
||||
ViewSetBase,
|
||||
MetadataAttributesFunctionalEndpoint,
|
||||
MetadataAttributesFunctionalBase,
|
||||
TestCase
|
||||
):
|
||||
|
||||
viewset_type = 'detail'
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(self):
|
||||
|
||||
super().setUpTestData()
|
||||
|
||||
self.url_kwargs = self.url_view_kwargs
|
@ -450,15 +450,6 @@ class CommonViewSetTestCases(
|
||||
}
|
||||
}
|
||||
|
||||
# @classmethod
|
||||
# def setUpTestData(self):
|
||||
|
||||
# self.kwargs: dict = {}
|
||||
|
||||
# if self.viewset is CommonViewSet:
|
||||
|
||||
# self.viewset.model = Organization
|
||||
|
||||
|
||||
def test_class_inherits_organizationmixin(self, viewset):
|
||||
"""Class Inheritence check
|
||||
@ -707,34 +698,6 @@ class ModelViewSetBaseCases(
|
||||
},
|
||||
}
|
||||
|
||||
# kwargs: dict = {}
|
||||
|
||||
# organization: Organization
|
||||
|
||||
# view_user: User
|
||||
|
||||
# @classmethod
|
||||
# def setUpTestData(self):
|
||||
|
||||
# super().setUpTestData() # Sets attribute self.view_set.model
|
||||
|
||||
# self.organization = Organization.objects.create(name='test_org')
|
||||
|
||||
# self.view_user = User.objects.create_user(
|
||||
# username="test_view_user1278", password="password", is_superuser=True)
|
||||
|
||||
|
||||
# @classmethod
|
||||
# def tearDownClass(cls):
|
||||
|
||||
# cls.model = None
|
||||
|
||||
# cls.organization.delete()
|
||||
|
||||
# cls.view_user.delete()
|
||||
|
||||
# super().tearDownClass()
|
||||
|
||||
|
||||
def test_class_inherits_modelviewsetbase(self, viewset):
|
||||
"""Class Inheritence check
|
||||
@ -756,21 +719,6 @@ class ModelViewSetBaseCases(
|
||||
|
||||
view_set = viewset_mock_request
|
||||
|
||||
# view_set.request = MockRequest(
|
||||
# user = self.view_user,
|
||||
# model = getattr(self, 'model',None),
|
||||
# organization = self.organization,
|
||||
# viewset = self.viewset,
|
||||
# )
|
||||
|
||||
# view_set.request.headers = {}
|
||||
|
||||
# view_set.kwargs = self.kwargs
|
||||
|
||||
# view_set.action = 'list'
|
||||
|
||||
# view_set.detail = False
|
||||
|
||||
assert view_set.queryset is None # Must be empty before init
|
||||
|
||||
q = view_set.get_queryset()
|
||||
@ -1078,14 +1026,6 @@ class SubModelViewSetTestCases(
|
||||
}
|
||||
}
|
||||
|
||||
# kwargs: dict
|
||||
|
||||
# organization: Organization
|
||||
|
||||
# view_user: User
|
||||
|
||||
# viewset = SubModelViewSet
|
||||
|
||||
|
||||
def test_class_inherits_submodelviewsetbase(self, viewset):
|
||||
"""Class Inheritence check
|
||||
@ -2245,19 +2185,6 @@ class SubModelViewSetInheritedCases(
|
||||
Use this Test Suite for ViewSet classes that inherit from SubModelViewSet
|
||||
"""
|
||||
|
||||
# @classmethod
|
||||
# def setUpTestData(self):
|
||||
# """Setup Test
|
||||
|
||||
# 1. make list request
|
||||
# """
|
||||
|
||||
# self.viewset.kwargs = {}
|
||||
|
||||
# self.viewset.kwargs[self.viewset.model_kwarg] = self.model._meta.sub_model_type
|
||||
|
||||
# super().setUpTestData()
|
||||
|
||||
|
||||
@pytest.fixture( scope = 'function' )
|
||||
def viewset_mock_request(self, django_db_blocker, viewset,
|
||||
|
@ -17,3 +17,9 @@ def model_kwargs(request, kwargs_authtoken):
|
||||
|
||||
if hasattr(request.cls, 'kwargs_create_item'):
|
||||
del request.cls.kwargs_create_item
|
||||
|
||||
|
||||
@pytest.fixture( scope = 'class')
|
||||
def model_serializer(serializer_authtoken):
|
||||
|
||||
yield serializer_authtoken
|
||||
|
@ -1,187 +0,0 @@
|
||||
import django
|
||||
import pytest
|
||||
|
||||
from django.contrib.auth.models import Permission
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.shortcuts import reverse
|
||||
from django.test import Client, TestCase
|
||||
|
||||
from access.models.tenant import Tenant as Organization
|
||||
from access.models.team import Team
|
||||
from access.models.team_user import TeamUsers
|
||||
|
||||
from api.models.tokens import AuthToken
|
||||
from api.tests.abstract.api_fields import APIModelFields
|
||||
|
||||
User = django.contrib.auth.get_user_model()
|
||||
|
||||
|
||||
|
||||
@pytest.mark.model_authtoken
|
||||
@pytest.mark.module_api
|
||||
class API(
|
||||
TestCase,
|
||||
APIModelFields
|
||||
):
|
||||
|
||||
model = AuthToken
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(self):
|
||||
"""Setup Test
|
||||
|
||||
1. Create an organization for user and item
|
||||
2. Create an item
|
||||
|
||||
"""
|
||||
|
||||
self.organization = Organization.objects.create(name='test_org')
|
||||
|
||||
|
||||
self.view_user = User.objects.create_user(username="test_user_view", password="password")
|
||||
|
||||
self.item = self.model.objects.create(
|
||||
note = 'a note',
|
||||
token = self.model().generate,
|
||||
user = self.view_user,
|
||||
expires = '2099-02-26T00:53Z'
|
||||
)
|
||||
|
||||
self.url_view_kwargs = {
|
||||
'model_id': self.view_user.id,
|
||||
'pk': self.item.id
|
||||
}
|
||||
|
||||
view_permissions = Permission.objects.get(
|
||||
codename = 'view_' + self.model._meta.model_name,
|
||||
content_type = ContentType.objects.get(
|
||||
app_label = self.model._meta.app_label,
|
||||
model = self.model._meta.model_name,
|
||||
)
|
||||
)
|
||||
|
||||
view_team = Team.objects.create(
|
||||
team_name = 'view_team',
|
||||
organization = self.organization,
|
||||
)
|
||||
|
||||
view_team.permissions.set([view_permissions])
|
||||
|
||||
teamuser = TeamUsers.objects.create(
|
||||
team = view_team,
|
||||
user = self.view_user
|
||||
)
|
||||
|
||||
client = Client()
|
||||
url = reverse('v2:_api_authtoken-detail', kwargs=self.url_view_kwargs)
|
||||
|
||||
|
||||
client.force_login(self.view_user)
|
||||
response = client.get(url)
|
||||
|
||||
self.api_data = response.data
|
||||
|
||||
|
||||
|
||||
def test_api_field_exists_model_notes(self):
|
||||
""" Test for existance of API Field
|
||||
|
||||
This test case is a duplicate of a test with the same name. This
|
||||
model is not a tenancy model and does not require this field.
|
||||
|
||||
model_notes field must exist
|
||||
"""
|
||||
|
||||
assert 'model_notes' not in self.api_data
|
||||
|
||||
|
||||
def test_api_field_type_model_notes(self):
|
||||
""" Test for type for API Field
|
||||
|
||||
This test case is a duplicate of a test with the same name. This
|
||||
model is not a tenancy model and does not require this field.
|
||||
|
||||
model_notes field must be str
|
||||
"""
|
||||
|
||||
assert 'model_notes' not in self.api_data
|
||||
|
||||
|
||||
|
||||
def test_api_field_exists_user(self):
|
||||
""" Test for existance of API Field
|
||||
|
||||
user field must exist
|
||||
"""
|
||||
|
||||
assert 'user' in self.api_data
|
||||
|
||||
|
||||
def test_api_field_type_user(self):
|
||||
""" Test for type for API Field
|
||||
|
||||
normallay an object would be serialized. However in this case only
|
||||
the owner of the object will access the object and therefore would
|
||||
be a waste to serialize it.
|
||||
|
||||
user field must be int
|
||||
"""
|
||||
|
||||
assert type(self.api_data['user']) is int
|
||||
|
||||
|
||||
|
||||
def test_api_field_exists_note(self):
|
||||
""" Test for existance of API Field
|
||||
|
||||
note field must exist
|
||||
"""
|
||||
|
||||
assert 'note' in self.api_data
|
||||
|
||||
|
||||
def test_api_field_type_user(self):
|
||||
""" Test for type for API Field
|
||||
|
||||
note field must be str
|
||||
"""
|
||||
|
||||
assert type(self.api_data['note']) is str
|
||||
|
||||
|
||||
|
||||
def test_api_field_exists_expires(self):
|
||||
""" Test for existance of API Field
|
||||
|
||||
expires field must exist
|
||||
"""
|
||||
|
||||
assert 'expires' in self.api_data
|
||||
|
||||
|
||||
def test_api_field_type_expires(self):
|
||||
""" Test for type for API Field
|
||||
|
||||
expires field must be str
|
||||
"""
|
||||
|
||||
assert type(self.api_data['expires']) is str
|
||||
|
||||
|
||||
|
||||
# def test_api_field_exists_url_history(self):
|
||||
# """ Test for existance of API Field
|
||||
|
||||
# _urls.history field must exist
|
||||
# """
|
||||
|
||||
# assert 'history' in self.api_data['_urls']
|
||||
|
||||
|
||||
# def test_api_field_type_url_history(self):
|
||||
# """ Test for type for API Field
|
||||
|
||||
# _urls.history field must be str
|
||||
# """
|
||||
|
||||
# assert type(self.api_data['_urls']['history']) is str
|
@ -10,8 +10,7 @@ from core.tests.unit.mixin_centurion.test_unit_centurion_mixin import CenturionM
|
||||
|
||||
|
||||
|
||||
@pytest.mark.unit
|
||||
@pytest.mark.centurion_models
|
||||
@pytest.mark.model_authtoken
|
||||
class AuthTokenModelTestCases(
|
||||
CenturionMixnInheritedCases,
|
||||
):
|
||||
@ -139,6 +138,7 @@ class AuthTokenModelInheritedCases(
|
||||
|
||||
|
||||
|
||||
@pytest.mark.module_api
|
||||
class AuthTokenModelPyTest(
|
||||
AuthTokenModelTestCases,
|
||||
):
|
279
app/api/tests/unit/token/test_unit_auth_token_serializer.py
Normal file
279
app/api/tests/unit/token/test_unit_auth_token_serializer.py
Normal file
@ -0,0 +1,279 @@
|
||||
import pytest
|
||||
|
||||
from django.db import models
|
||||
|
||||
from rest_framework.exceptions import (
|
||||
PermissionDenied,
|
||||
ValidationError,
|
||||
)
|
||||
|
||||
from api.tests.unit.test_unit_serializer import (
|
||||
SerializerTestCases
|
||||
)
|
||||
|
||||
from centurion.tests.abstract.mock_view import MockView
|
||||
|
||||
|
||||
|
||||
@pytest.mark.model_authtoken
|
||||
class AuthTokenSerializerTestCases(
|
||||
SerializerTestCases
|
||||
):
|
||||
|
||||
|
||||
@pytest.fixture( scope = 'function' )
|
||||
def created_model(self, django_db_blocker, model, model_kwargs):
|
||||
|
||||
with django_db_blocker.unblock():
|
||||
|
||||
kwargs_many_to_many = {}
|
||||
|
||||
kwargs = {}
|
||||
|
||||
for key, value in model_kwargs.items():
|
||||
|
||||
field = model._meta.get_field(key)
|
||||
|
||||
if isinstance(field, models.ManyToManyField):
|
||||
|
||||
kwargs_many_to_many.update({
|
||||
key: value
|
||||
})
|
||||
|
||||
else:
|
||||
|
||||
kwargs.update({
|
||||
key: value
|
||||
})
|
||||
|
||||
|
||||
item = model.objects.create( **kwargs )
|
||||
|
||||
for key, value in kwargs_many_to_many.items():
|
||||
|
||||
field = getattr(item, key)
|
||||
|
||||
for entry in value:
|
||||
|
||||
field.add(entry)
|
||||
|
||||
yield item
|
||||
|
||||
item.delete()
|
||||
|
||||
|
||||
def test_serializer_is_valid(self, kwargs_api_create, model, model_serializer, request_user):
|
||||
|
||||
mock_view = MockView(
|
||||
user = request_user,
|
||||
model = model,
|
||||
action = 'create',
|
||||
)
|
||||
|
||||
mock_view.kwargs = {
|
||||
'model_id': request_user.id
|
||||
}
|
||||
|
||||
serializer = model_serializer['model'](
|
||||
context = {
|
||||
'request': mock_view.request,
|
||||
'view': mock_view,
|
||||
},
|
||||
data = kwargs_api_create
|
||||
)
|
||||
|
||||
assert serializer.is_valid(raise_exception = True)
|
||||
|
||||
|
||||
|
||||
@pytest.mark.regression
|
||||
def test_serializer_create_calls_model_full_clean(self,
|
||||
kwargs_api_create, mocker, model, model_serializer, request_user
|
||||
):
|
||||
|
||||
|
||||
mock_view = MockView(
|
||||
user = request_user,
|
||||
model = model,
|
||||
action = 'create',
|
||||
)
|
||||
|
||||
mock_view.kwargs = {
|
||||
'model_id': request_user.id
|
||||
}
|
||||
|
||||
serializer = model_serializer['model'](
|
||||
context = {
|
||||
'request': mock_view.request,
|
||||
'view': mock_view,
|
||||
},
|
||||
data = kwargs_api_create
|
||||
)
|
||||
|
||||
serializer.is_valid(raise_exception = True)
|
||||
|
||||
full_clean = mocker.spy(model, 'full_clean')
|
||||
|
||||
serializer.save()
|
||||
|
||||
full_clean.assert_called_once()
|
||||
|
||||
|
||||
# def test_serializer_validation_no_title(self,
|
||||
# kwargs_api_create, model, model_serializer, request_user
|
||||
# ):
|
||||
# """Serializer Validation Check
|
||||
|
||||
# Ensure that if creating and no title is provided a validation error occurs
|
||||
# """
|
||||
|
||||
# mock_view = MockView(
|
||||
# user = request_user,
|
||||
# model = model,
|
||||
# action = 'create',
|
||||
# )
|
||||
|
||||
# kwargs = kwargs_api_create.copy()
|
||||
# del kwargs['title']
|
||||
|
||||
# with pytest.raises(ValidationError) as err:
|
||||
|
||||
# serializer = model_serializer['model'](
|
||||
# context = {
|
||||
# 'request': mock_view.request,
|
||||
# 'view': mock_view,
|
||||
# },
|
||||
# data = kwargs
|
||||
# )
|
||||
|
||||
# serializer.is_valid(raise_exception = True)
|
||||
|
||||
# assert err.value.get_codes()['title'][0] == 'required'
|
||||
|
||||
|
||||
|
||||
def test_serializer_validation_valid_data_different_user(self,
|
||||
kwargs_api_create, model, model_serializer, request_user
|
||||
):
|
||||
"""Serializer Validation Check
|
||||
|
||||
Ensure that if adding the same manufacturer
|
||||
it raises a validation error
|
||||
"""
|
||||
|
||||
mock_view = MockView(
|
||||
user = request_user,
|
||||
model = model,
|
||||
action = 'create',
|
||||
)
|
||||
|
||||
kwargs = kwargs_api_create.copy()
|
||||
|
||||
mock_view.kwargs = {
|
||||
'model_id': 99999
|
||||
}
|
||||
|
||||
with pytest.raises(PermissionDenied) as err:
|
||||
|
||||
serializer = model_serializer['model'](
|
||||
context = {
|
||||
'request': mock_view.request,
|
||||
'view': mock_view,
|
||||
},
|
||||
data = kwargs
|
||||
)
|
||||
|
||||
serializer.is_valid(raise_exception = True)
|
||||
|
||||
assert err.value.get_codes() == 'permission_denied'
|
||||
|
||||
|
||||
|
||||
def test_serializer_validation_valid_data_token_not_sha256_same_length(self,
|
||||
kwargs_api_create, model, model_serializer, request_user
|
||||
):
|
||||
"""Serializer Validation Check
|
||||
|
||||
Ensure that if adding the same manufacturer
|
||||
it raises a validation error
|
||||
"""
|
||||
|
||||
mock_view = MockView(
|
||||
user = request_user,
|
||||
model = model,
|
||||
action = 'create',
|
||||
)
|
||||
|
||||
mock_view.kwargs = {
|
||||
'model_id': request_user.id
|
||||
}
|
||||
|
||||
kwargs = kwargs_api_create.copy()
|
||||
kwargs['token'] = str( model().generate )[:-5] + 'qwert'
|
||||
|
||||
with pytest.raises(ValidationError) as err:
|
||||
|
||||
serializer = model_serializer['model'](
|
||||
context = {
|
||||
'request': mock_view.request,
|
||||
'view': mock_view,
|
||||
},
|
||||
data = kwargs
|
||||
)
|
||||
|
||||
serializer.is_valid(raise_exception = True)
|
||||
|
||||
assert err.value.get_codes()['token'][0] == 'token_not_sha256'
|
||||
|
||||
|
||||
|
||||
def test_serializer_validation_valid_data_token_not_sha256_wrong_length(self,
|
||||
kwargs_api_create, model, model_serializer, request_user
|
||||
):
|
||||
"""Serializer Validation Check
|
||||
|
||||
Ensure that if adding the same manufacturer
|
||||
it raises a validation error
|
||||
"""
|
||||
|
||||
mock_view = MockView(
|
||||
user = request_user,
|
||||
model = model,
|
||||
action = 'create',
|
||||
)
|
||||
|
||||
mock_view.kwargs = {
|
||||
'model_id': request_user.id
|
||||
}
|
||||
|
||||
kwargs = kwargs_api_create.copy()
|
||||
kwargs['token'] = str( model().generate )[:-5] + 'qwer'
|
||||
|
||||
with pytest.raises(ValidationError) as err:
|
||||
|
||||
serializer = model_serializer['model'](
|
||||
context = {
|
||||
'request': mock_view.request,
|
||||
'view': mock_view,
|
||||
},
|
||||
data = kwargs
|
||||
)
|
||||
|
||||
serializer.is_valid(raise_exception = True)
|
||||
|
||||
assert err.value.get_codes()['token'][0] == 'token_not_sha256'
|
||||
|
||||
|
||||
|
||||
class AuthTokenSerializerInheritedCases(
|
||||
AuthTokenSerializerTestCases
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@pytest.mark.module_api
|
||||
class AuthTokenSerializerPyTest(
|
||||
AuthTokenSerializerTestCases
|
||||
):
|
||||
pass
|
@ -1,52 +1,90 @@
|
||||
import pytest
|
||||
|
||||
from django.test import Client, TestCase
|
||||
|
||||
from rest_framework.reverse import reverse
|
||||
|
||||
from api.tests.unit.test_unit_common_viewset import (
|
||||
ModelCreateViewSetInheritedCases,
|
||||
ModelListRetrieveDeleteViewSetInheritedCases,
|
||||
)
|
||||
from api.viewsets.auth_token import ViewSet
|
||||
|
||||
from api.viewsets.auth_token import (
|
||||
AuthToken,
|
||||
ViewSet,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@pytest.mark.skip(reason = 'see #895, tests being refactored')
|
||||
@pytest.mark.model_authtoken
|
||||
@pytest.mark.module_api
|
||||
class ViewsetList(
|
||||
class ViewsetTestCases(
|
||||
ModelCreateViewSetInheritedCases,
|
||||
ModelListRetrieveDeleteViewSetInheritedCases,
|
||||
TestCase,
|
||||
):
|
||||
|
||||
viewset = ViewSet
|
||||
|
||||
route_name = 'v2:_api_authtoken'
|
||||
@pytest.fixture( scope = 'function' )
|
||||
def viewset(self):
|
||||
return ViewSet
|
||||
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(self):
|
||||
"""Setup Test
|
||||
|
||||
1. make list request
|
||||
"""
|
||||
|
||||
super().setUpTestData()
|
||||
|
||||
self.kwargs = {
|
||||
'model_id': self.view_user.id
|
||||
@property
|
||||
def parameterized_class_attributes(self):
|
||||
return {
|
||||
'_log': {
|
||||
'type': type(None),
|
||||
},
|
||||
'_model_documentation': {
|
||||
'type': type(None),
|
||||
},
|
||||
'back_url': {
|
||||
'type': type(None),
|
||||
},
|
||||
'documentation': {
|
||||
'type': type(None),
|
||||
'value': None
|
||||
},
|
||||
'filterset_fields': {
|
||||
'value': [
|
||||
'expires'
|
||||
]
|
||||
},
|
||||
'model': {
|
||||
'value': AuthToken
|
||||
},
|
||||
'model_documentation': {
|
||||
'type': type(None),
|
||||
},
|
||||
'queryset': {
|
||||
'type': type(None),
|
||||
},
|
||||
'serializer_class': {
|
||||
'type': type(None),
|
||||
},
|
||||
'search_fields': {
|
||||
'value': [
|
||||
'note'
|
||||
]
|
||||
},
|
||||
'view_description': {
|
||||
'value': 'User Authentication Tokens'
|
||||
},
|
||||
'view_name': {
|
||||
'type': type(None),
|
||||
},
|
||||
'view_serializer_name': {
|
||||
'type': type(None),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
client = Client()
|
||||
|
||||
url = reverse(
|
||||
self.route_name + '-list',
|
||||
kwargs = self.kwargs
|
||||
)
|
||||
|
||||
client.force_login(self.view_user)
|
||||
class AuthTokenViewsetInheritedCases(
|
||||
ViewsetTestCases,
|
||||
):
|
||||
pass
|
||||
|
||||
self.http_options_response_list = client.options(url)
|
||||
|
||||
|
||||
@pytest.mark.module_api
|
||||
class AuthTokenViewsetPyTest(
|
||||
ViewsetTestCases,
|
||||
):
|
||||
|
||||
pass
|
||||
|
@ -61,22 +61,22 @@ router = DefaultRouter(trailing_slash=False)
|
||||
router.register('', v2.Index, basename='_api_v2_home')
|
||||
|
||||
|
||||
router.register('base', base_index_v2.Index, basename='_api_v2_base_home')
|
||||
router.register('base/content_type', content_type_v2.ViewSet, basename='_api_v2_content_type')
|
||||
router.register('base/permission', permission_v2.ViewSet, basename='_api_v2_permission')
|
||||
router.register('base/user', user_v2.ViewSet, basename='_api_v2_user')
|
||||
router.register('/base', base_index_v2.Index, basename='_api_v2_base_home')
|
||||
router.register('/base/content_type', content_type_v2.ViewSet, basename='_api_v2_content_type')
|
||||
router.register('/base/permission', permission_v2.ViewSet, basename='_api_v2_permission')
|
||||
router.register('/base/user', user_v2.ViewSet, basename='_api_v2_user')
|
||||
|
||||
|
||||
|
||||
router.register(
|
||||
prefix = f'(?P<app_label>[{history_app_labels}]+)/(?P<model_name>[{history_type_names} \
|
||||
prefix = f'/(?P<app_label>[{history_app_labels}]+)/(?P<model_name>[{history_type_names} \
|
||||
]+)/(?P<model_id>[0-9]+)/history',
|
||||
viewset = audit_history.ViewSet,
|
||||
basename = '_api_centurionaudit_sub'
|
||||
)
|
||||
|
||||
router.register(
|
||||
prefix = f'(?P<app_label>[{notes_app_labels}]+)/(?P<model_name>[{notes_type_names} \
|
||||
prefix = f'/(?P<app_label>[{notes_app_labels}]+)/(?P<model_name>[{notes_type_names} \
|
||||
]+)/(?P<model_id>[0-9]+)/notes',
|
||||
viewset = centurion_model_notes.ViewSet,
|
||||
basename = '_api_centurionmodelnote_sub'
|
||||
@ -85,24 +85,24 @@ router.register(
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
path('schema', SpectacularAPIView.as_view(api_version='v2'), name='schema-v2',),
|
||||
path('docs', SpectacularSwaggerView.as_view(url_name='schema-v2'), name='_api_v2_docs'),
|
||||
path('/schema', SpectacularAPIView.as_view(api_version='v2'), name='schema-v2',),
|
||||
path('/docs', SpectacularSwaggerView.as_view(url_name='schema-v2'), name='_api_v2_docs'),
|
||||
|
||||
]
|
||||
|
||||
urlpatterns += router.urls
|
||||
|
||||
urlpatterns += [
|
||||
path(route = "access/", view = include("access.urls_api")),
|
||||
path(route = "accounting/", view = include("accounting.urls")),
|
||||
path(route = "assistance/", view = include("assistance.urls_api")),
|
||||
path(route = "config_management/", view = include("config_management.urls_api")),
|
||||
path(route = "core/", view = include("core.urls_api")),
|
||||
path(route = "devops/", view = include("devops.urls")),
|
||||
path(route = "hr/", view = include('human_resources.urls')),
|
||||
path(route = "itam/", view = include("itam.urls_api")),
|
||||
path(route = "itim/", view = include("itim.urls_api")),
|
||||
path(route = "project_management/", view = include("project_management.urls_api")),
|
||||
path(route = "settings/", view = include("settings.urls_api")),
|
||||
path(route = 'public/', view = include('api.urls_public')),
|
||||
path(route = "/access", view = include("access.urls_api")),
|
||||
path(route = "/accounting", view = include("accounting.urls")),
|
||||
path(route = "/assistance", view = include("assistance.urls_api")),
|
||||
path(route = "/config_management", view = include("config_management.urls_api")),
|
||||
path(route = "/core", view = include("core.urls_api")),
|
||||
path(route = "/devops", view = include("devops.urls")),
|
||||
path(route = "/hr", view = include('human_resources.urls')),
|
||||
path(route = "/itam", view = include("itam.urls_api")),
|
||||
path(route = "/itim", view = include("itim.urls_api")),
|
||||
path(route = "/project_management", view = include("project_management.urls_api")),
|
||||
path(route = "/settings", view = include("settings.urls_api")),
|
||||
path(route = '/public', view = include('api.urls_public')),
|
||||
]
|
||||
|
@ -1,16 +1,19 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-03 22:04
|
||||
# Generated by Django 5.1.10 on 2025-08-15 03:21
|
||||
|
||||
import access.models.tenancy_abstract
|
||||
import assistance.models.model_knowledge_base_article
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0010_company_alter_entity_entity_type_alter_person_dob_and_more"),
|
||||
("access", "0011_remove_entitynotes_model_and_more"),
|
||||
("assistance", "0006_alter_knowledgebase_organization_and_more"),
|
||||
("core", "0027_centurionmodelnote"),
|
||||
("core", "0024_centurionaudit_centurionmodelnote_and_more"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
@ -22,6 +25,48 @@ class Migration(migrations.Migration):
|
||||
model_name="knowledgebasecategory",
|
||||
name="is_global",
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="knowledgebase",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebase",
|
||||
name="category",
|
||||
field=models.ForeignKey(
|
||||
help_text="Article Category",
|
||||
max_length=50,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="assistance.knowledgebasecategory",
|
||||
verbose_name="Category",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebase",
|
||||
name="content",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Content of the article. Markdown is supported",
|
||||
null=True,
|
||||
verbose_name="Article Content",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebase",
|
||||
name="expiry_date",
|
||||
field=models.DateTimeField(
|
||||
blank=True,
|
||||
help_text="Date the article will be removed from published articles",
|
||||
null=True,
|
||||
verbose_name="End Date",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebase",
|
||||
name="id",
|
||||
@ -47,6 +92,72 @@ class Migration(migrations.Migration):
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebase",
|
||||
name="release_date",
|
||||
field=models.DateTimeField(
|
||||
blank=True,
|
||||
help_text="Date the article will be published",
|
||||
null=True,
|
||||
verbose_name="Publish Date",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebase",
|
||||
name="responsible_teams",
|
||||
field=models.ManyToManyField(
|
||||
blank=True,
|
||||
help_text="Team(s) whom is considered the articles owner.",
|
||||
related_name="responsible_teams",
|
||||
to="access.team",
|
||||
verbose_name="Responsible Team(s)",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebase",
|
||||
name="responsible_user",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="User(s) whom is considered the articles owner.",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="responsible_user",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Responsible User",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebase",
|
||||
name="summary",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Short Summary of the article",
|
||||
null=True,
|
||||
verbose_name="Summary",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebase",
|
||||
name="target_team",
|
||||
field=models.ManyToManyField(
|
||||
blank=True,
|
||||
help_text="Team(s) to grant access to the article",
|
||||
to="access.team",
|
||||
verbose_name="Target Team(s)",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebase",
|
||||
name="target_user",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="User(s) to grant access to the article",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Target Users(s)",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebasecategory",
|
||||
name="model_notes",
|
||||
@ -70,5 +181,181 @@ class Migration(migrations.Migration):
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
)
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebasecategory",
|
||||
name="parent_category",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="Category this category belongs to",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
to="assistance.knowledgebasecategory",
|
||||
verbose_name="Parent Category",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebasecategory",
|
||||
name="target_team",
|
||||
field=models.ManyToManyField(
|
||||
blank=True,
|
||||
help_text="Team(s) to grant access to the article",
|
||||
to="access.team",
|
||||
verbose_name="Target Team(s)",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebasecategory",
|
||||
name="target_user",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="User(s) to grant access to the article",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Target Users(s)",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="modelknowledgebasearticle",
|
||||
name="model",
|
||||
field=models.CharField(
|
||||
choices=assistance.models.model_knowledge_base_article.all_models,
|
||||
help_text="Model type to link to article article",
|
||||
max_length=80,
|
||||
verbose_name="Model Type",
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="KnowledgeBaseAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="assistance.knowledgebase",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Knowledge Base History",
|
||||
"verbose_name_plural": "Knowledge Base Histories",
|
||||
"db_table": "assistance_knowledgebase_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="KnowledgeBaseCategoryAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="assistance.knowledgebasecategory",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Knowledge Base Category History",
|
||||
"verbose_name_plural": "Knowledge Base Category Histories",
|
||||
"db_table": "assistance_knowledgebasecategory_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="KnowledgeBaseCategoryCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="assistance.knowledgebasecategory",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Knowledge Base Category Note",
|
||||
"verbose_name_plural": "Knowledge Base Category Notes",
|
||||
"db_table": "assistance_knowledgebasecategory_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="KnowledgeBaseCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="assistance.knowledgebase",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Knowledge Base Note",
|
||||
"verbose_name_plural": "Knowledge Base Notes",
|
||||
"db_table": "assistance_knowledgebase_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
]
|
||||
|
@ -1,81 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-03 22:06
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("assistance", "0007_remove_knowledgebase_is_global_and_more"),
|
||||
("core", "0027_centurionmodelnote"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="KnowledgeBaseAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="assistance.knowledgebase",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Knowledge Base History",
|
||||
"verbose_name_plural": "Knowledge Base Histories",
|
||||
"db_table": "assistance_knowledgebase_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit", models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="KnowledgeBaseCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="assistance.knowledgebase",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Knowledge Base Note",
|
||||
"verbose_name_plural": "Knowledge Base Notes",
|
||||
"db_table": "assistance_knowledgebase_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote", models.Model),
|
||||
),
|
||||
]
|
@ -1,81 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-03 22:07
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("assistance", "0008_knowledgebaseaudithistory_and_more"),
|
||||
("core", "0027_centurionmodelnote"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="KnowledgeBaseCategoryAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="assistance.knowledgebasecategory",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Knowledge Base Category History",
|
||||
"verbose_name_plural": "Knowledge Base Category Histories",
|
||||
"db_table": "assistance_knowledgebasecategory_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit", models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="KnowledgeBaseCategoryCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="assistance.knowledgebasecategory",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Knowledge Base Category Note",
|
||||
"verbose_name_plural": "Knowledge Base Category Notes",
|
||||
"db_table": "assistance_knowledgebasecategory_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote", models.Model),
|
||||
),
|
||||
]
|
@ -1,114 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-03 23:40
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0010_company_alter_entity_entity_type_alter_person_dob_and_more"),
|
||||
("assistance", "0009_knowledgebasecategoryaudithistory_and_more"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebase",
|
||||
name="category",
|
||||
field=models.ForeignKey(
|
||||
help_text="Article Category",
|
||||
max_length=50,
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="assistance.knowledgebasecategory",
|
||||
verbose_name="Category",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebase",
|
||||
name="content",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Content of the article. Markdown is supported",
|
||||
null=True,
|
||||
verbose_name="Article Content",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebase",
|
||||
name="expiry_date",
|
||||
field=models.DateTimeField(
|
||||
blank=True,
|
||||
help_text="Date the article will be removed from published articles",
|
||||
null=True,
|
||||
verbose_name="End Date",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebase",
|
||||
name="release_date",
|
||||
field=models.DateTimeField(
|
||||
blank=True,
|
||||
help_text="Date the article will be published",
|
||||
null=True,
|
||||
verbose_name="Publish Date",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebase",
|
||||
name="responsible_teams",
|
||||
field=models.ManyToManyField(
|
||||
blank=True,
|
||||
help_text="Team(s) whom is considered the articles owner.",
|
||||
related_name="responsible_teams",
|
||||
to="access.team",
|
||||
verbose_name="Responsible Team(s)",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebase",
|
||||
name="responsible_user",
|
||||
field=models.ForeignKey(
|
||||
help_text="User(s) whom is considered the articles owner.",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="responsible_user",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Responsible User",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebase",
|
||||
name="summary",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Short Summary of the article",
|
||||
null=True,
|
||||
verbose_name="Summary",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebase",
|
||||
name="target_team",
|
||||
field=models.ManyToManyField(
|
||||
blank=True,
|
||||
help_text="Team(s) to grant access to the article",
|
||||
to="access.team",
|
||||
verbose_name="Target Team(s)",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebase",
|
||||
name="target_user",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="User(s) to grant access to the article",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Target Users(s)",
|
||||
),
|
||||
),
|
||||
]
|
@ -1,23 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-03 23:56
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("assistance", "0010_alter_knowledgebase_category_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name="knowledgebase",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
]
|
@ -1,51 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-04 00:23
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0010_company_alter_entity_entity_type_alter_person_dob_and_more"),
|
||||
("assistance", "0011_knowledgebase_model_notes"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebasecategory",
|
||||
name="parent_category",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="Category this category belongs to",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
to="assistance.knowledgebasecategory",
|
||||
verbose_name="Parent Category",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebasecategory",
|
||||
name="target_team",
|
||||
field=models.ManyToManyField(
|
||||
blank=True,
|
||||
help_text="Team(s) to grant access to the article",
|
||||
to="access.team",
|
||||
verbose_name="Target Team(s)",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebasecategory",
|
||||
name="target_user",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="User(s) to grant access to the article",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.SET_NULL,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Target Users(s)",
|
||||
),
|
||||
),
|
||||
]
|
@ -1,24 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-06 02:40
|
||||
|
||||
import assistance.models.model_knowledge_base_article
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("assistance", "0012_alter_knowledgebasecategory_parent_category_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="modelknowledgebasearticle",
|
||||
name="model",
|
||||
field=models.CharField(
|
||||
choices=assistance.models.model_knowledge_base_article.all_models,
|
||||
help_text="Model type to link to article article",
|
||||
max_length=80,
|
||||
verbose_name="Model Type",
|
||||
),
|
||||
),
|
||||
]
|
@ -1,29 +0,0 @@
|
||||
# Generated by Django 5.1.10 on 2025-07-29 04:13
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("assistance", "0013_alter_modelknowledgebasearticle_model"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="knowledgebase",
|
||||
name="responsible_user",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="User(s) whom is considered the articles owner.",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="responsible_user",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Responsible User",
|
||||
),
|
||||
),
|
||||
]
|
@ -19,16 +19,16 @@ router.register(
|
||||
basename = '_api_v2_assistance_home'
|
||||
)
|
||||
router.register(
|
||||
prefix = 'knowledge_base', viewset = knowledge_base_v2.ViewSet,
|
||||
prefix = '/knowledge_base', viewset = knowledge_base_v2.ViewSet,
|
||||
basename = '_api_knowledgebase'
|
||||
)
|
||||
router.register(
|
||||
prefix = '(?P<model>.+)/(?P<model_pk>[0-9]+)/knowledge_base',
|
||||
prefix = '/(?P<model>.+)/(?P<model_pk>[0-9]+)/knowledge_base',
|
||||
viewset = model_knowledge_base_article.ViewSet,
|
||||
basename = '_api_v2_model_kb'
|
||||
)
|
||||
router.register(
|
||||
prefix = 'ticket/request', viewset = request_ticket_v2.ViewSet,
|
||||
prefix = '/ticket/request', viewset = request_ticket_v2.ViewSet,
|
||||
basename = '_api_v2_ticket_request'
|
||||
)
|
||||
|
||||
|
@ -20,6 +20,7 @@ import django.db.models.options as options
|
||||
|
||||
options.DEFAULT_NAMES = (*options.DEFAULT_NAMES, 'sub_model_type', 'itam_sub_model_type')
|
||||
|
||||
APPEND_SLASH = False
|
||||
AUTH_USER_MODEL = 'auth.User'
|
||||
|
||||
# Build paths inside the project like this: BASE_DIR / 'subdir'.
|
||||
|
182
app/centurion/tests/integration/test_integration_list_urls.py
Normal file
182
app/centurion/tests/integration/test_integration_list_urls.py
Normal file
@ -0,0 +1,182 @@
|
||||
|
||||
import pytest
|
||||
import re
|
||||
import requests
|
||||
|
||||
from django.urls import get_resolver, URLPattern, URLResolver
|
||||
|
||||
|
||||
|
||||
def list_urls(urlpatterns, parent_pattern=''):
|
||||
|
||||
urls = []
|
||||
|
||||
for entry in urlpatterns:
|
||||
|
||||
if isinstance(entry, URLPattern):
|
||||
urls.append(parent_pattern + str(entry.pattern))
|
||||
|
||||
elif isinstance(entry, URLResolver):
|
||||
urls.extend(list_urls(entry.url_patterns, parent_pattern + str(entry.pattern)))
|
||||
|
||||
filtered = [
|
||||
re.sub(r"\^([a-z\-]+)\$$", r"\1", u).rstrip('/') for u in urls if (
|
||||
re.sub(r"\^([a-z\-]+)\$$", r"\1", u).startswith('api/')
|
||||
and '(' not in re.sub(r"\^([a-z\-]+)\$$", r"\1", u).rstrip('/')
|
||||
and '<' not in re.sub(r"\^([a-z\-]+)\$$", r"\1", u).rstrip('/')
|
||||
and '$' not in re.sub(r"\^([a-z\-]+)\$$", r"\1", u).rstrip('/')
|
||||
)
|
||||
]
|
||||
|
||||
return filtered
|
||||
|
||||
|
||||
no_auth_urls = [
|
||||
'api/v2/auth/login',
|
||||
'api/v2/docs',
|
||||
'api/v2/schema',
|
||||
]
|
||||
|
||||
urls_list_view_auth_required_excluded = [
|
||||
'api/v2/auth/logout',
|
||||
|
||||
]
|
||||
|
||||
urls_list_view_auth_required_authenticated_excluded = [
|
||||
'api/v2/itam/inventory',
|
||||
'api/v2/auth/logout',
|
||||
]
|
||||
|
||||
@pytest.mark.integration
|
||||
@pytest.mark.regression
|
||||
class URLChecksPyTest:
|
||||
|
||||
|
||||
|
||||
@pytest.fixture(scope="class")
|
||||
def auto_login_client(self):
|
||||
session = requests.Session()
|
||||
|
||||
login_page_url = "http://127.0.0.1:8003/api/v2/auth/login"
|
||||
login_post_url = "http://127.0.0.1:8003/api/v2/auth/login"
|
||||
|
||||
resp = session.get(login_page_url)
|
||||
resp.raise_for_status()
|
||||
# Extract CSRF token from cookies (Django sets csrftoken cookie)
|
||||
csrf_token = session.cookies.get("csrftoken")
|
||||
if not csrf_token:
|
||||
raise RuntimeError("CSRF token cookie not found")
|
||||
|
||||
login_data = {
|
||||
"username": "admin",
|
||||
"password": "admin",
|
||||
"csrfmiddlewaretoken": csrf_token,
|
||||
}
|
||||
|
||||
headers = {
|
||||
"Referer": login_page_url,
|
||||
"X-CSRFToken": csrf_token, # Include CSRF token header
|
||||
}
|
||||
|
||||
resp = session.post(login_post_url, data=login_data, headers=headers, allow_redirects=True)
|
||||
resp.raise_for_status()
|
||||
|
||||
|
||||
class Client:
|
||||
def __init__(self, session):
|
||||
self._session = session
|
||||
|
||||
self._unauth_session = requests.Session()
|
||||
|
||||
resp = self._unauth_session.get(login_page_url)
|
||||
resp.raise_for_status()
|
||||
self._headers = csrf_token = {
|
||||
"Referer": login_page_url,
|
||||
"X-CSRFToken": self._unauth_session.cookies.get("csrftoken"),
|
||||
}
|
||||
|
||||
def request(self, method, url, auth = False, **kwargs):
|
||||
|
||||
if auth:
|
||||
session = self._session
|
||||
else:
|
||||
session = self._unauth_session
|
||||
|
||||
return session.request(method, url, headers=self._headers, **kwargs)
|
||||
|
||||
@property
|
||||
def cookies(self):
|
||||
return self._session.cookies
|
||||
|
||||
return Client(session)
|
||||
|
||||
|
||||
list_view_urls = list_urls(urlpatterns = get_resolver().url_patterns)
|
||||
|
||||
|
||||
|
||||
@pytest.mark.parametrize(
|
||||
argnames = "url_path",
|
||||
argvalues = [
|
||||
url for url in list_view_urls if( url in no_auth_urls )
|
||||
],
|
||||
ids = [
|
||||
re.sub(r'[^\w_\-.:]', '_', url) for url in list_view_urls if( url in no_auth_urls )
|
||||
],
|
||||
)
|
||||
def test_urls_no_auth_required(self, url_path, auto_login_client):
|
||||
url = f"http://127.0.0.1:8003/{url_path}"
|
||||
|
||||
response = auto_login_client.request("GET", url)
|
||||
|
||||
assert response.status_code == 200
|
||||
|
||||
|
||||
|
||||
@pytest.mark.permissions
|
||||
@pytest.mark.parametrize(
|
||||
argnames = "url_path",
|
||||
argvalues = [
|
||||
url for url in list_view_urls if(
|
||||
url not in no_auth_urls
|
||||
and url not in urls_list_view_auth_required_excluded
|
||||
)
|
||||
],
|
||||
ids = [
|
||||
re.sub(r'[^\w_\-.:]', '_', url) for url in list_view_urls if(
|
||||
url not in no_auth_urls
|
||||
and url not in urls_list_view_auth_required_excluded
|
||||
)
|
||||
],
|
||||
)
|
||||
def test_urls_list_view_auth_required(self, url_path, auto_login_client):
|
||||
url = f"http://127.0.0.1:8003/{url_path}"
|
||||
|
||||
response = auto_login_client.request("GET", url)
|
||||
|
||||
assert response.status_code == 401
|
||||
|
||||
|
||||
|
||||
@pytest.mark.permissions
|
||||
@pytest.mark.parametrize(
|
||||
argnames = "url_path",
|
||||
argvalues = [
|
||||
url for url in list_view_urls if(
|
||||
url not in no_auth_urls
|
||||
and url not in urls_list_view_auth_required_authenticated_excluded
|
||||
)
|
||||
],
|
||||
ids = [
|
||||
re.sub(r'[^\w_\-.:]', '_', url) for url in list_view_urls if(
|
||||
url not in no_auth_urls
|
||||
and url not in urls_list_view_auth_required_authenticated_excluded
|
||||
)
|
||||
],
|
||||
)
|
||||
def test_urls_list_view_auth_required_authenticated(self, url_path, auto_login_client):
|
||||
url = f"http://127.0.0.1:8003/{url_path}"
|
||||
|
||||
response = auto_login_client.request(method = "GET", url = url, auth = True)
|
||||
|
||||
assert response.status_code == 200
|
@ -4,14 +4,14 @@ from django.contrib.auth import views as auth_views
|
||||
from django.views.static import serve
|
||||
from django.urls import include, path, re_path
|
||||
|
||||
|
||||
from rest_framework import urls
|
||||
|
||||
urlpatterns = [
|
||||
path('admin/', admin.site.urls, name='_administration'),
|
||||
path('admin', admin.site.urls, name='_administration'),
|
||||
|
||||
path('account/password_change/', auth_views.PasswordChangeView.as_view(template_name="password_change.html.j2"), name="change_password"),
|
||||
path('account/password_change', auth_views.PasswordChangeView.as_view(template_name="password_change.html.j2"), name="change_password"),
|
||||
|
||||
path("account/", include("django.contrib.auth.urls")),
|
||||
path("account", include("django.contrib.auth.urls")),
|
||||
|
||||
re_path(r'^static/(?P<path>.*)$', serve,{'document_root': settings.STATIC_ROOT}),
|
||||
|
||||
@ -30,15 +30,16 @@ if settings.API_ENABLED:
|
||||
|
||||
urlpatterns += [
|
||||
|
||||
path("api/", include("api.urls", namespace = 'v1')),
|
||||
path("api", include("api.urls", namespace = 'v1')),
|
||||
|
||||
path("api/v2/", include("api.urls_v2", namespace = 'v2')),
|
||||
path("api/v2", include("api.urls_v2", namespace = 'v2')),
|
||||
|
||||
]
|
||||
|
||||
|
||||
urlpatterns += [
|
||||
path('api/v2/auth/', include('rest_framework.urls')),
|
||||
path('api/v2/auth/login', auth_views.LoginView.as_view(template_name='rest_framework/login.html'), name='login'),
|
||||
path('api/v2/auth/logout', auth_views.LogoutView.as_view(), name='logout'),
|
||||
]
|
||||
|
||||
|
||||
|
@ -0,0 +1,359 @@
|
||||
# Generated by Django 5.1.10 on 2025-08-15 03:21
|
||||
|
||||
import access.models.tenancy_abstract
|
||||
import config_management.models.groups
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0011_remove_entitynotes_model_and_more"),
|
||||
("config_management", "0008_alter_configgrouphosts_organization_and_more"),
|
||||
("core", "0024_centurionaudit_centurionmodelnote_and_more"),
|
||||
("itam", "0012_remove_device_is_global_remove_device_slug_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name="configgrouphosts",
|
||||
name="is_global",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="configgroups",
|
||||
name="is_global",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="configgroupsoftware",
|
||||
name="is_global",
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgrouphosts",
|
||||
name="group",
|
||||
field=models.ForeignKey(
|
||||
help_text="Group that this host is part of",
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="config_management.configgroups",
|
||||
verbose_name="Group",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgrouphosts",
|
||||
name="host",
|
||||
field=models.ForeignKey(
|
||||
help_text="Host that will be apart of this config group",
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="itam.device",
|
||||
validators=[
|
||||
config_management.models.groups.ConfigGroupHosts.validate_host_no_parent_group
|
||||
],
|
||||
verbose_name="Host",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgrouphosts",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgrouphosts",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgrouphosts",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgroups",
|
||||
name="config",
|
||||
field=models.JSONField(
|
||||
blank=True,
|
||||
help_text="Configuration for this Group",
|
||||
null=True,
|
||||
validators=[
|
||||
config_management.models.groups.ConfigGroups.validate_config_keys_not_reserved
|
||||
],
|
||||
verbose_name="Configuration",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgroups",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgroups",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgroups",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgroups",
|
||||
name="parent",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="Parent of this Group",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="config_management.configgroups",
|
||||
verbose_name="Parent Group",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgroupsoftware",
|
||||
name="action",
|
||||
field=models.IntegerField(
|
||||
blank=True,
|
||||
choices=[(1, "Install"), (0, "Remove")],
|
||||
help_text="ACtion to perform with this software",
|
||||
null=True,
|
||||
verbose_name="Action",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgroupsoftware",
|
||||
name="config_group",
|
||||
field=models.ForeignKey(
|
||||
help_text="Config group this softwre will be linked to",
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="config_management.configgroups",
|
||||
verbose_name="Config Group",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgroupsoftware",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgroupsoftware",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgroupsoftware",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgroupsoftware",
|
||||
name="software",
|
||||
field=models.ForeignKey(
|
||||
help_text="Software to add to this config Group",
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="itam.software",
|
||||
verbose_name="Software",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgroupsoftware",
|
||||
name="version",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="Software Version for this config group",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="itam.softwareversion",
|
||||
verbose_name="Verrsion",
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ConfigGroupHostsAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="config_management.configgrouphosts",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "config group hosts History",
|
||||
"verbose_name_plural": "config group hosts Histories",
|
||||
"db_table": "config_management_configgrouphosts_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ConfigGroupsAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="config_management.configgroups",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Config Group History",
|
||||
"verbose_name_plural": "Config Group Histories",
|
||||
"db_table": "config_management_configgroups_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ConfigGroupsCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="config_management.configgroups",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Config Group Note",
|
||||
"verbose_name_plural": "Config Group Notes",
|
||||
"db_table": "config_management_configgroups_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ConfigGroupSoftwareAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="config_management.configgroupsoftware",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Config Group Software History",
|
||||
"verbose_name_plural": "Config Group Software Histories",
|
||||
"db_table": "config_management_configgroupsoftware_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
]
|
@ -1,122 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-06 02:40
|
||||
|
||||
import access.models.tenancy_abstract
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0012_teamusers_model_notes_alter_teamusers_id_and_more"),
|
||||
("config_management", "0008_alter_configgrouphosts_organization_and_more"),
|
||||
("core", "0028_delete_history"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name="configgroups",
|
||||
name="is_global",
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgroups",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgroups",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgroups",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ConfigGroupsAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="config_management.configgroups",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Config Group History",
|
||||
"verbose_name_plural": "Config Group Histories",
|
||||
"db_table": "config_management_configgroups_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit", models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ConfigGroupsCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="config_management.configgroups",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Config Group Note",
|
||||
"verbose_name_plural": "Config Group Notes",
|
||||
"db_table": "config_management_configgroups_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote", models.Model),
|
||||
),
|
||||
]
|
@ -1,122 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-06 02:42
|
||||
|
||||
import access.models.tenancy_abstract
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0012_teamusers_model_notes_alter_teamusers_id_and_more"),
|
||||
("config_management", "0009_remove_configgroups_is_global_and_more"),
|
||||
("core", "0028_delete_history"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name="configgrouphosts",
|
||||
name="is_global",
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgrouphosts",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgrouphosts",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgrouphosts",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ConfigGroupHostsAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="config_management.configgrouphosts",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "config group hosts History",
|
||||
"verbose_name_plural": "config group hosts Histories",
|
||||
"db_table": "config_management_configgrouphosts_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit", models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ConfigGroupHostsCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="config_management.configgrouphosts",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "config group hosts Note",
|
||||
"verbose_name_plural": "config group hosts Notes",
|
||||
"db_table": "config_management_configgrouphosts_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote", models.Model),
|
||||
)
|
||||
]
|
@ -1,122 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-06 02:43
|
||||
|
||||
import access.models.tenancy_abstract
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0012_teamusers_model_notes_alter_teamusers_id_and_more"),
|
||||
("config_management", "0010_remove_configgroupsoftware_is_global_and_more"),
|
||||
("core", "0028_delete_history"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name="configgroupsoftware",
|
||||
name="is_global",
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgroupsoftware",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgroupsoftware",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgroupsoftware",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ConfigGroupSoftwareAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="config_management.configgroupsoftware",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Config Group Software History",
|
||||
"verbose_name_plural": "Config Group Software Histories",
|
||||
"db_table": "config_management_configgroupsoftware_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit", models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ConfigGroupSoftwareCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="config_management.configgroupsoftware",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Config Group Software Note",
|
||||
"verbose_name_plural": "Config Group Software Notes",
|
||||
"db_table": "config_management_configgroupsoftware_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote", models.Model),
|
||||
),
|
||||
]
|
@ -1,40 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-07 03:57
|
||||
|
||||
import config_management.models.groups
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("config_management", "0011_remove_configgroupsoftware_is_global_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="configgroups",
|
||||
name="config",
|
||||
field=models.JSONField(
|
||||
blank=True,
|
||||
help_text="Configuration for this Group",
|
||||
null=True,
|
||||
validators=[
|
||||
config_management.models.groups.ConfigGroups.validate_config_keys_not_reserved
|
||||
],
|
||||
verbose_name="Configuration",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgroups",
|
||||
name="parent",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="Parent of this Group",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="config_management.configgroups",
|
||||
verbose_name="Parent Group",
|
||||
),
|
||||
),
|
||||
]
|
@ -1,61 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-07 04:10
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
(
|
||||
"config_management",
|
||||
"0012_alter_configgroups_config_alter_configgroups_parent",
|
||||
),
|
||||
("itam", "0014_remove_device_is_global_remove_device_slug_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="configgroupsoftware",
|
||||
name="action",
|
||||
field=models.IntegerField(
|
||||
blank=True,
|
||||
choices=[(1, "Install"), (0, "Remove")],
|
||||
help_text="ACtion to perform with this software",
|
||||
null=True,
|
||||
verbose_name="Action",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgroupsoftware",
|
||||
name="config_group",
|
||||
field=models.ForeignKey(
|
||||
help_text="Config group this softwre will be linked to",
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="config_management.configgroups",
|
||||
verbose_name="Config Group",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgroupsoftware",
|
||||
name="software",
|
||||
field=models.ForeignKey(
|
||||
help_text="Software to add to this config Group",
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="itam.software",
|
||||
verbose_name="Software",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgroupsoftware",
|
||||
name="version",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="Software Version for this config group",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="itam.softwareversion",
|
||||
verbose_name="Verrsion",
|
||||
),
|
||||
),
|
||||
]
|
@ -1,39 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-07 04:11
|
||||
|
||||
import config_management.models.groups
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("config_management", "0013_alter_configgroupsoftware_action_and_more"),
|
||||
("itam", "0014_remove_device_is_global_remove_device_slug_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="configgrouphosts",
|
||||
name="group",
|
||||
field=models.ForeignKey(
|
||||
help_text="Group that this host is part of",
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="config_management.configgroups",
|
||||
verbose_name="Group",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="configgrouphosts",
|
||||
name="host",
|
||||
field=models.ForeignKey(
|
||||
help_text="Host that will be apart of this config group",
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="itam.device",
|
||||
validators=[
|
||||
config_management.models.groups.ConfigGroupHosts.validate_host_no_parent_group
|
||||
],
|
||||
verbose_name="Host",
|
||||
),
|
||||
),
|
||||
]
|
@ -1,27 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-07 08:17
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("config_management", "0014_alter_configgrouphosts_group_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name="configgroupsoftwarecenturionmodelnote",
|
||||
name="centurionmodelnote_ptr",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="configgroupsoftwarecenturionmodelnote",
|
||||
name="model",
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name="ConfigGroupHostsCenturionModelNote",
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name="ConfigGroupSoftwareCenturionModelNote",
|
||||
),
|
||||
]
|
@ -18,15 +18,15 @@ router.register(
|
||||
basename = '_api_v2_config_management_home'
|
||||
)
|
||||
router.register(
|
||||
prefix = 'group', viewset = config_group_v2.ViewSet,
|
||||
prefix = '/group', viewset = config_group_v2.ViewSet,
|
||||
basename = '_api_configgroups'
|
||||
)
|
||||
router.register(
|
||||
prefix = 'group/(?P<parent_group>[0-9]+)/child_group', viewset = config_group_v2.ViewSet,
|
||||
prefix = '/group/(?P<parent_group>[0-9]+)/child_group', viewset = config_group_v2.ViewSet,
|
||||
basename = '_api_configgroups_child'
|
||||
)
|
||||
router.register(
|
||||
prefix = 'group/(?P<config_group_id>[0-9]+)/software',
|
||||
prefix = '/group/(?P<config_group_id>[0-9]+)/software',
|
||||
viewset = config_group_software_v2.ViewSet,
|
||||
basename = '_api_configgroupsoftware'
|
||||
)
|
||||
|
@ -1,42 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-05-20 16:20
|
||||
|
||||
import access.fields
|
||||
import access.models.tenancy_abstract
|
||||
import core.models.centurion
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('access', '0010_company_alter_entity_entity_type_alter_person_dob_and_more'),
|
||||
('contenttypes', '0002_remove_content_type_name'),
|
||||
('core', '0023_ticketcommentaction_alter_manufacturer_organization_and_more'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='CenturionAudit',
|
||||
fields=[
|
||||
('id', models.AutoField(help_text='ID of the item', primary_key=True, serialize=False, unique=True, verbose_name='ID')),
|
||||
('model_notes', models.TextField(blank=True, help_text='Tid bits of information', null=True, verbose_name='Notes')),
|
||||
('created', access.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, help_text='Date and time of creation', verbose_name='Created')),
|
||||
('before', models.JSONField(blank=True, default=None, help_text='Value before Change', null=True, validators=[core.models.centurion.CenturionModel.validate_field_not_none], verbose_name='Before')),
|
||||
('after', models.JSONField(blank=True, default=None, help_text='Value Change to', null=True, validators=[core.models.centurion.CenturionModel.validate_field_not_none], verbose_name='After')),
|
||||
('action', models.IntegerField(choices=[(1, 'Create'), (2, 'Update'), (3, 'Delete')], default=None, help_text='History action performed', null=True, validators=[core.models.centurion.CenturionModel.validate_field_not_none], verbose_name='Action')),
|
||||
('content_type', models.ForeignKey(blank=True, help_text='Model this history is for', on_delete=django.db.models.deletion.CASCADE, to='contenttypes.contenttype', validators=[core.models.centurion.CenturionModel.validate_field_not_none], verbose_name='Content Model')),
|
||||
('organization', models.ForeignKey(help_text='Tenant this belongs to', on_delete=django.db.models.deletion.CASCADE, related_name='+', to='access.tenant', validators=[access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists], verbose_name='Tenant')),
|
||||
('user', models.ForeignKey(help_text='User whom performed the action', null=True, on_delete=django.db.models.deletion.DO_NOTHING, to=settings.AUTH_USER_MODEL, validators=[core.models.centurion.CenturionModel.validate_field_not_none], verbose_name='User')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Model History',
|
||||
'verbose_name_plural': 'Model Histories',
|
||||
'db_table': 'core_audithistory',
|
||||
'ordering': ['-created'],
|
||||
},
|
||||
),
|
||||
]
|
@ -0,0 +1,662 @@
|
||||
# Generated by Django 5.1.10 on 2025-08-15 03:21
|
||||
|
||||
import access.fields
|
||||
import access.models.tenancy_abstract
|
||||
import core.models.centurion
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0010_company_alter_entity_entity_type_alter_person_dob_and_more"),
|
||||
("assistance", "0006_alter_knowledgebase_organization_and_more"),
|
||||
("contenttypes", "0002_remove_content_type_name"),
|
||||
("core", "0023_ticketcommentaction_alter_manufacturer_organization_and_more"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="CenturionAudit",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"created",
|
||||
access.fields.AutoCreatedField(
|
||||
default=django.utils.timezone.now,
|
||||
editable=False,
|
||||
help_text="Date and time of creation",
|
||||
verbose_name="Created",
|
||||
),
|
||||
),
|
||||
(
|
||||
"before",
|
||||
models.JSONField(
|
||||
blank=True,
|
||||
help_text="Value before Change",
|
||||
null=True,
|
||||
validators=[
|
||||
core.models.centurion.CenturionModel.validate_field_not_none
|
||||
],
|
||||
verbose_name="Before",
|
||||
),
|
||||
),
|
||||
(
|
||||
"after",
|
||||
models.JSONField(
|
||||
blank=True,
|
||||
help_text="Value Change to",
|
||||
null=True,
|
||||
validators=[
|
||||
core.models.centurion.CenturionModel.validate_field_not_none
|
||||
],
|
||||
verbose_name="After",
|
||||
),
|
||||
),
|
||||
(
|
||||
"action",
|
||||
models.IntegerField(
|
||||
choices=[(1, "Create"), (2, "Update"), (3, "Delete")],
|
||||
help_text="History action performed",
|
||||
null=True,
|
||||
validators=[
|
||||
core.models.centurion.CenturionModel.validate_field_not_none
|
||||
],
|
||||
verbose_name="Action",
|
||||
),
|
||||
),
|
||||
(
|
||||
"content_type",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="Model this history is for",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="contenttypes.contenttype",
|
||||
validators=[
|
||||
core.models.centurion.CenturionModel.validate_field_not_none
|
||||
],
|
||||
verbose_name="Content Model",
|
||||
),
|
||||
),
|
||||
(
|
||||
"organization",
|
||||
models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
(
|
||||
"user",
|
||||
models.ForeignKey(
|
||||
help_text="User whom performed the action",
|
||||
on_delete=django.db.models.deletion.DO_NOTHING,
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
validators=[
|
||||
core.models.centurion.CenturionModel.validate_field_not_none
|
||||
],
|
||||
verbose_name="User",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Model History",
|
||||
"verbose_name_plural": "Model Histories",
|
||||
"db_table": "core_audithistory",
|
||||
"ordering": ["-created"],
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="CenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"created",
|
||||
access.fields.AutoCreatedField(
|
||||
default=django.utils.timezone.now,
|
||||
editable=False,
|
||||
help_text="Date and time of creation",
|
||||
verbose_name="Created",
|
||||
),
|
||||
),
|
||||
(
|
||||
"body",
|
||||
models.TextField(
|
||||
help_text="The tid bit of information you wish to add",
|
||||
verbose_name="Note",
|
||||
),
|
||||
),
|
||||
(
|
||||
"modified",
|
||||
access.fields.AutoLastModifiedField(
|
||||
default=django.utils.timezone.now,
|
||||
editable=False,
|
||||
help_text="Date and time of last modification",
|
||||
verbose_name="Modified",
|
||||
),
|
||||
),
|
||||
(
|
||||
"content_type",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="Model this note is for",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="contenttypes.contenttype",
|
||||
verbose_name="Content Model",
|
||||
),
|
||||
),
|
||||
(
|
||||
"created_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="User whom added the Note",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="+",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Created By",
|
||||
),
|
||||
),
|
||||
(
|
||||
"modified_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="User whom modified the note",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="+",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Edited By",
|
||||
),
|
||||
),
|
||||
(
|
||||
"organization",
|
||||
models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Centurion Model Note",
|
||||
"verbose_name_plural": "Centurion Model Notes",
|
||||
"ordering": ["-created"],
|
||||
},
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="manufacturer",
|
||||
name="is_global",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="manufacturer",
|
||||
name="slug",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="ticketcategory",
|
||||
name="is_global",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="ticketcommentcategory",
|
||||
name="is_global",
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="manufacturer",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="manufacturer",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketbase",
|
||||
name="external_ref",
|
||||
field=models.IntegerField(
|
||||
blank=True,
|
||||
help_text="External System reference",
|
||||
null=True,
|
||||
verbose_name="Reference Number",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketbase",
|
||||
name="external_system",
|
||||
field=models.IntegerField(
|
||||
blank=True,
|
||||
choices=[
|
||||
(1, "Github"),
|
||||
(2, "Gitlab"),
|
||||
(9999, "Custom #1 (Imported)"),
|
||||
(9998, "Custom #2 (Imported)"),
|
||||
(9997, "Custom #3 (Imported)"),
|
||||
(9996, "Custom #4 (Imported)"),
|
||||
(9995, "Custom #5 (Imported)"),
|
||||
(9994, "Custom #6 (Imported)"),
|
||||
(9993, "Custom #7 (Imported)"),
|
||||
(9992, "Custom #8 (Imported)"),
|
||||
(9991, "Custom #9 (Imported)"),
|
||||
],
|
||||
help_text="External system this item derives",
|
||||
null=True,
|
||||
verbose_name="External System",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketbase",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketbase",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketcategory",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketcategory",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketcategory",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketcategory",
|
||||
name="parent",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="The Parent Category",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="core.ticketcategory",
|
||||
verbose_name="Parent Category",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketcategory",
|
||||
name="runbook",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="The runbook for this category",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="assistance.knowledgebase",
|
||||
verbose_name="Runbook",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketcommentbase",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketcommentbase",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketcommentcategory",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketcommentcategory",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketcommentcategory",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketcommentcategory",
|
||||
name="parent",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="The Parent Category",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="core.ticketcommentcategory",
|
||||
verbose_name="Parent Category",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketcommentcategory",
|
||||
name="runbook",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="The runbook for this category",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="assistance.knowledgebase",
|
||||
verbose_name="Runbook",
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ManufacturerAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="core.manufacturer",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Manufacturer History",
|
||||
"verbose_name_plural": "Manufacturer Histories",
|
||||
"db_table": "core_manufacturer_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="TicketCategoryAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="core.ticketcategory",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Ticket Category History",
|
||||
"verbose_name_plural": "Ticket Category Histories",
|
||||
"db_table": "core_ticketcategory_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="TicketCommentCategoryAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="core.ticketcommentcategory",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Ticket Comment Category History",
|
||||
"verbose_name_plural": "Ticket Comment Category Histories",
|
||||
"db_table": "core_ticketcommentcategory_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ManufacturerCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="core.manufacturer",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Manufacturer Note",
|
||||
"verbose_name_plural": "Manufacturer Notes",
|
||||
"db_table": "core_manufacturer_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="TicketCategoryCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="core.ticketcategory",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Ticket Category Note",
|
||||
"verbose_name_plural": "Ticket Category Notes",
|
||||
"db_table": "core_ticketcategory_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="TicketCommentCategoryCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="core.ticketcommentcategory",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Ticket Comment Category Note",
|
||||
"verbose_name_plural": "Ticket Comment Category Notes",
|
||||
"db_table": "core_ticketcommentcategory_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name="History",
|
||||
),
|
||||
]
|
@ -1,38 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-05-24 17:20
|
||||
|
||||
import core.models.centurion
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0024_centurionaudit'),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='centurionaudit',
|
||||
name='action',
|
||||
field=models.IntegerField(choices=[(1, 'Create'), (2, 'Update'), (3, 'Delete')], help_text='History action performed', null=True, validators=[core.models.centurion.CenturionModel.validate_field_not_none], verbose_name='Action'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='centurionaudit',
|
||||
name='after',
|
||||
field=models.JSONField(blank=True, help_text='Value Change to', null=True, validators=[core.models.centurion.CenturionModel.validate_field_not_none], verbose_name='After'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='centurionaudit',
|
||||
name='before',
|
||||
field=models.JSONField(blank=True, help_text='Value before Change', null=True, validators=[core.models.centurion.CenturionModel.validate_field_not_none], verbose_name='Before'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='centurionaudit',
|
||||
name='user',
|
||||
field=models.ForeignKey(default=None, help_text='User whom performed the action', on_delete=django.db.models.deletion.DO_NOTHING, to=settings.AUTH_USER_MODEL, validators=[core.models.centurion.CenturionModel.validate_field_not_none], verbose_name='User'),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
@ -1,17 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-05-24 22:39
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('core', '0025_alter_centurionaudit_action_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='centurionaudit',
|
||||
name='model_notes',
|
||||
),
|
||||
]
|
@ -1,112 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-05-29 04:03
|
||||
|
||||
import access.fields
|
||||
import access.models.tenancy_abstract
|
||||
import django.db.models.deletion
|
||||
import django.utils.timezone
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0010_company_alter_entity_entity_type_alter_person_dob_and_more"),
|
||||
("contenttypes", "0002_remove_content_type_name"),
|
||||
("core", "0026_remove_centurionaudit_model_notes"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="CenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"id",
|
||||
models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
(
|
||||
"created",
|
||||
access.fields.AutoCreatedField(
|
||||
default=django.utils.timezone.now,
|
||||
editable=False,
|
||||
help_text="Date and time of creation",
|
||||
verbose_name="Created",
|
||||
),
|
||||
),
|
||||
(
|
||||
"body",
|
||||
models.TextField(
|
||||
help_text="The tid bit of information you wish to add",
|
||||
verbose_name="Note",
|
||||
),
|
||||
),
|
||||
(
|
||||
"modified",
|
||||
access.fields.AutoLastModifiedField(
|
||||
default=django.utils.timezone.now,
|
||||
editable=False,
|
||||
help_text="Date and time of last modification",
|
||||
verbose_name="Modified",
|
||||
),
|
||||
),
|
||||
(
|
||||
"content_type",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="Model this note is for",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="contenttypes.contenttype",
|
||||
verbose_name="Content Model",
|
||||
),
|
||||
),
|
||||
(
|
||||
"created_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="User whom added the Note",
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="+",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Created By",
|
||||
),
|
||||
),
|
||||
(
|
||||
"modified_by",
|
||||
models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="User whom modified the note",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="+",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Edited By",
|
||||
),
|
||||
),
|
||||
(
|
||||
"organization",
|
||||
models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Centurion Model Note",
|
||||
"verbose_name_plural": "Centurion Model Notes",
|
||||
"ordering": ["-created"],
|
||||
},
|
||||
),
|
||||
]
|
@ -1,16 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-05 06:24
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("core", "0027_centurionmodelnote"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel(
|
||||
name="History",
|
||||
),
|
||||
]
|
@ -1,114 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-06 02:55
|
||||
|
||||
import access.models.tenancy_abstract
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0012_teamusers_model_notes_alter_teamusers_id_and_more"),
|
||||
("core", "0028_delete_history"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name="manufacturer",
|
||||
name="is_global",
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name="manufacturer",
|
||||
name="slug",
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="manufacturer",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="manufacturer",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ManufacturerAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="core.manufacturer",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Manufacturer History",
|
||||
"verbose_name_plural": "Manufacturer Histories",
|
||||
"db_table": "core_manufacturer_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit", models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="ManufacturerCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="core.manufacturer",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Manufacturer Note",
|
||||
"verbose_name_plural": "Manufacturer Notes",
|
||||
"db_table": "core_manufacturer_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote", models.Model),
|
||||
),
|
||||
]
|
@ -1,121 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-06 03:05
|
||||
|
||||
import access.models.tenancy_abstract
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0012_teamusers_model_notes_alter_teamusers_id_and_more"),
|
||||
("core", "0029_remove_manufacturer_is_global_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name="ticketcommentcategory",
|
||||
name="is_global",
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketcommentcategory",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketcommentcategory",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketcommentcategory",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="TicketCommentCategoryAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="core.ticketcommentcategory",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Ticket Comment Category History",
|
||||
"verbose_name_plural": "Ticket Comment Category Histories",
|
||||
"db_table": "core_ticketcommentcategory_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit", models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="TicketCommentCategoryCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="core.ticketcommentcategory",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Ticket Comment Category Note",
|
||||
"verbose_name_plural": "Ticket Comment Category Notes",
|
||||
"db_table": "core_ticketcommentcategory_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote", models.Model),
|
||||
),
|
||||
]
|
@ -1,121 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-06 03:08
|
||||
|
||||
import access.models.tenancy_abstract
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0012_teamusers_model_notes_alter_teamusers_id_and_more"),
|
||||
("core", "0030_remove_ticketcommentcategory_is_global_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name="ticketcategory",
|
||||
name="is_global",
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketcategory",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketcategory",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketcategory",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="TicketCategoryAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="core.ticketcategory",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Ticket Category History",
|
||||
"verbose_name_plural": "Ticket Category Histories",
|
||||
"db_table": "core_ticketcategory_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit", models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="TicketCategoryCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="core.ticketcategory",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Ticket Category Note",
|
||||
"verbose_name_plural": "Ticket Category Notes",
|
||||
"db_table": "core_ticketcategory_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote", models.Model),
|
||||
),
|
||||
]
|
@ -1,39 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-09 00:20
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("assistance", "0013_alter_modelknowledgebasearticle_model"),
|
||||
("core", "0031_remove_ticketcategory_is_global_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="ticketcategory",
|
||||
name="parent",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="The Parent Category",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="core.ticketcategory",
|
||||
verbose_name="Parent Category",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketcategory",
|
||||
name="runbook",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="The runbook for this category",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="assistance.knowledgebase",
|
||||
verbose_name="Runbook",
|
||||
),
|
||||
),
|
||||
]
|
@ -1,39 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-09 00:26
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("assistance", "0013_alter_modelknowledgebasearticle_model"),
|
||||
("core", "0032_alter_ticketcategory_parent_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="ticketcommentcategory",
|
||||
name="parent",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="The Parent Category",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="core.ticketcommentcategory",
|
||||
verbose_name="Parent Category",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketcommentcategory",
|
||||
name="runbook",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="The runbook for this category",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
to="assistance.knowledgebase",
|
||||
verbose_name="Runbook",
|
||||
),
|
||||
),
|
||||
]
|
@ -1,41 +0,0 @@
|
||||
# Generated by Django 5.1.10 on 2025-07-13 13:22
|
||||
|
||||
import access.models.tenancy_abstract
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0021_roleaudithistory_rolecenturionmodelnote"),
|
||||
("core", "0033_alter_ticketcommentcategory_parent_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="ticketbase",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketbase",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
]
|
@ -1,41 +0,0 @@
|
||||
# Generated by Django 5.1.10 on 2025-07-13 13:28
|
||||
|
||||
import access.models.tenancy_abstract
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0021_roleaudithistory_rolecenturionmodelnote"),
|
||||
("core", "0034_alter_ticketbase_id_alter_ticketbase_organization"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="ticketcommentbase",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketcommentbase",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
]
|
@ -1,46 +0,0 @@
|
||||
# Generated by Django 5.1.10 on 2025-07-14 16:20
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("core", "0035_alter_ticketcommentbase_id_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="ticketbase",
|
||||
name="external_ref",
|
||||
field=models.IntegerField(
|
||||
blank=True,
|
||||
help_text="External System reference",
|
||||
null=True,
|
||||
verbose_name="Reference Number",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="ticketbase",
|
||||
name="external_system",
|
||||
field=models.IntegerField(
|
||||
blank=True,
|
||||
choices=[
|
||||
(1, "Github"),
|
||||
(2, "Gitlab"),
|
||||
(9999, "Custom #1 (Imported)"),
|
||||
(9998, "Custom #2 (Imported)"),
|
||||
(9997, "Custom #3 (Imported)"),
|
||||
(9996, "Custom #4 (Imported)"),
|
||||
(9995, "Custom #5 (Imported)"),
|
||||
(9994, "Custom #6 (Imported)"),
|
||||
(9993, "Custom #7 (Imported)"),
|
||||
(9992, "Custom #8 (Imported)"),
|
||||
(9991, "Custom #9 (Imported)"),
|
||||
],
|
||||
help_text="External system this item derives",
|
||||
null=True,
|
||||
verbose_name="External System",
|
||||
),
|
||||
),
|
||||
]
|
@ -1,42 +0,0 @@
|
||||
# Generated by Django 5.1.10 on 2025-07-23 00:04
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("contenttypes", "0002_remove_content_type_name"),
|
||||
("core", "0036_alter_ticketbase_external_ref_and_more"),
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="centurionmodelnote",
|
||||
name="content_type",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="Model this note is for",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
to="contenttypes.contenttype",
|
||||
verbose_name="Content Model",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="centurionmodelnote",
|
||||
name="created_by",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="User whom added the Note",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="+",
|
||||
to=settings.AUTH_USER_MODEL,
|
||||
verbose_name="Created By",
|
||||
),
|
||||
),
|
||||
]
|
@ -94,6 +94,12 @@ class ModelSerializer(
|
||||
]
|
||||
|
||||
|
||||
def validate(self, attrs):
|
||||
|
||||
attrs['created_by'] = self._context['request'].user
|
||||
|
||||
return super().validate(attrs)
|
||||
|
||||
|
||||
def is_valid(self, *, raise_exception=False) -> bool:
|
||||
|
||||
|
@ -1,4 +1,6 @@
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.db.models.signals import (
|
||||
post_migrate,
|
||||
)
|
||||
@ -14,6 +16,31 @@ def centurion_model_migrate(sender, **kwargs):
|
||||
if sender.label != 'core':
|
||||
return
|
||||
|
||||
try:
|
||||
|
||||
print('\n\nFetching System User.\n')
|
||||
|
||||
user = apps.get_model(settings.AUTH_USER_MODEL).objects.get(
|
||||
username = 'system'
|
||||
)
|
||||
|
||||
if user.is_active:
|
||||
print(' System user is set as "Active", disabling.\n')
|
||||
user.is_active = False
|
||||
|
||||
user.save()
|
||||
|
||||
except ObjectDoesNotExist:
|
||||
|
||||
print(' System user not found, creating.\n')
|
||||
|
||||
user = apps.get_model(settings.AUTH_USER_MODEL).objects.create(
|
||||
username = 'system',
|
||||
first_name = 'System',
|
||||
last_name = 'User',
|
||||
is_active = False,
|
||||
)
|
||||
|
||||
print('\n\nCenturion Model Migration Signal.....\n')
|
||||
|
||||
models: list[ dict ] = [
|
||||
@ -261,7 +288,7 @@ def centurion_model_migrate(sender, **kwargs):
|
||||
model_name = model.get_history_model_name( model )
|
||||
)
|
||||
|
||||
history = original_history.objects.filter().exclude( user = None )
|
||||
history = original_history.objects.filter()
|
||||
|
||||
print(f' Found {len(history)} history entries to migrate.')
|
||||
|
||||
@ -269,18 +296,28 @@ def centurion_model_migrate(sender, **kwargs):
|
||||
|
||||
try:
|
||||
|
||||
after = {}
|
||||
if entry.after:
|
||||
after = entry.after
|
||||
|
||||
entry_model = entry.model
|
||||
if hasattr(entry, 'child_model'):
|
||||
entry_model = entry.child_model
|
||||
|
||||
entry_user = entry.user
|
||||
|
||||
if not entry_user:
|
||||
|
||||
entry_user = user
|
||||
|
||||
migrated_history = audit_history.objects.create(
|
||||
organization = entry.organization,
|
||||
content_type = entry.content_type,
|
||||
model = entry_model,
|
||||
before = entry.before,
|
||||
after = entry.after,
|
||||
after = after,
|
||||
action = entry.action,
|
||||
user = entry.user,
|
||||
user = entry_user,
|
||||
created = entry.created
|
||||
)
|
||||
|
||||
|
@ -0,0 +1,218 @@
|
||||
import pytest
|
||||
|
||||
from django.apps import apps
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.utils.module_loading import import_string
|
||||
|
||||
from core.models.centurion_notes import CenturionModelNote
|
||||
|
||||
from api.tests.functional.test_functional_permissions_api import (
|
||||
APIPermissionsInheritedCases
|
||||
)
|
||||
|
||||
|
||||
|
||||
def get_models( excludes: list[ str ] = [] ) -> list[ tuple ]:
|
||||
"""Fetch models from Centurion Apps
|
||||
|
||||
Args:
|
||||
excludes (list[ str ]): Words that may be in a models name to exclude
|
||||
|
||||
Returns:
|
||||
list[ tuple ]: Centurion ERP Only models
|
||||
"""
|
||||
|
||||
models: list = []
|
||||
|
||||
model_apps: list = []
|
||||
|
||||
exclude_model_apps = [
|
||||
'django',
|
||||
'django_celery_results',
|
||||
'django_filters',
|
||||
'drf_spectacular',
|
||||
'drf_spectacular_sidecar',
|
||||
'coresheaders',
|
||||
'corsheaders',
|
||||
'rest_framework',
|
||||
'rest_framework_json_api',
|
||||
'social_django',
|
||||
]
|
||||
|
||||
for app in settings.INSTALLED_APPS:
|
||||
|
||||
app = app.split('.')[0]
|
||||
|
||||
if app in exclude_model_apps:
|
||||
continue
|
||||
|
||||
model_apps += [ app ]
|
||||
|
||||
|
||||
for model in apps.get_models():
|
||||
|
||||
if model._meta.app_label not in model_apps:
|
||||
continue
|
||||
|
||||
skip = False
|
||||
|
||||
for exclude in excludes:
|
||||
|
||||
if exclude in str(model._meta.model_name):
|
||||
skip = True
|
||||
break
|
||||
|
||||
if skip:
|
||||
continue
|
||||
|
||||
models += [ model ]
|
||||
|
||||
return models
|
||||
|
||||
|
||||
|
||||
class ModelNotesMetaAPIPermissionsTestCases(
|
||||
APIPermissionsInheritedCases
|
||||
):
|
||||
"""AuditHistory Meta Model Test Cases
|
||||
|
||||
This test suite is the base for the dynamic tests that are created
|
||||
during pytest discover.
|
||||
"""
|
||||
|
||||
@pytest.fixture( scope = 'class' )
|
||||
def note_model(self, request):
|
||||
|
||||
return request.cls.note_model_class
|
||||
|
||||
|
||||
@pytest.fixture( scope = 'class', autouse = True)
|
||||
def model_kwargs(self, django_db_blocker,
|
||||
request, note_model, kwargs_centurionmodelnotemeta
|
||||
):
|
||||
|
||||
model_kwargs = kwargs_centurionmodelnotemeta.copy()
|
||||
|
||||
with django_db_blocker.unblock():
|
||||
|
||||
note_model_kwargs = request.getfixturevalue('kwargs_' + note_model._meta.model_name)
|
||||
|
||||
kwargs = {}
|
||||
|
||||
many_field = {}
|
||||
|
||||
for field, value in note_model_kwargs.items():
|
||||
|
||||
if not hasattr(getattr(note_model, field), 'field'):
|
||||
continue
|
||||
|
||||
if isinstance(getattr(note_model, field).field, models.ManyToManyField):
|
||||
|
||||
if field in many_field:
|
||||
|
||||
many_field[field] += [ value ]
|
||||
|
||||
elif isinstance(value, list):
|
||||
|
||||
value_list = []
|
||||
|
||||
for list_value in value:
|
||||
|
||||
value_list += [ list_value ]
|
||||
|
||||
|
||||
value = value_list
|
||||
|
||||
else:
|
||||
|
||||
many_field.update({
|
||||
field: [
|
||||
value
|
||||
]
|
||||
})
|
||||
|
||||
continue
|
||||
|
||||
kwargs.update({
|
||||
field: value
|
||||
})
|
||||
|
||||
|
||||
model = note_model.objects.create(
|
||||
**kwargs
|
||||
)
|
||||
|
||||
|
||||
for field, values in many_field.items():
|
||||
|
||||
for value in values:
|
||||
|
||||
getattr(model, field).add( value )
|
||||
|
||||
|
||||
model_kwargs.update({
|
||||
'model': model
|
||||
})
|
||||
request.cls.kwargs_create_item = model_kwargs
|
||||
|
||||
yield model_kwargs
|
||||
|
||||
with django_db_blocker.unblock():
|
||||
|
||||
model.delete()
|
||||
|
||||
|
||||
@pytest.fixture( scope = 'class' )
|
||||
def model(self, request):
|
||||
|
||||
return request.cls.model_class
|
||||
|
||||
|
||||
@pytest.mark.skip( reason = 'ToDo: Figure out how to dynomagic add note_model instance' )
|
||||
def test_model_creation(self, model, user):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
for model in get_models():
|
||||
|
||||
if(
|
||||
not issubclass(model, CenturionModelNote)
|
||||
or model == CenturionModelNote
|
||||
):
|
||||
continue
|
||||
|
||||
|
||||
cls_name: str = f"{model._meta.object_name}MetaAPIPermissionsPyTest"
|
||||
|
||||
inc_classes = (ModelNotesMetaAPIPermissionsTestCases,)
|
||||
try:
|
||||
|
||||
additional_testcases = import_string(
|
||||
model._meta.app_label + '.tests.functional.additional_meta_model_note_' +
|
||||
str( model._meta.object_name ).replace('CenturionModelNote', '').lower() + '_permissions_api.AdditionalTestCases'
|
||||
)
|
||||
|
||||
inc_classes = (additional_testcases, *inc_classes)
|
||||
|
||||
except Exception as ex:
|
||||
additional_testcases = None
|
||||
|
||||
dynamic_class = type(
|
||||
cls_name,
|
||||
inc_classes,
|
||||
{
|
||||
'note_model_class': apps.get_model(
|
||||
app_label = model._meta.app_label,
|
||||
model_name = str( model._meta.object_name ).replace('CenturionModelNote', '')
|
||||
),
|
||||
'model_class': model
|
||||
}
|
||||
)
|
||||
|
||||
dynamic_class = pytest.mark.__getattr__(
|
||||
'model_' + str(model._meta.model_name).replace('centurionmodelnote', ''))(dynamic_class)
|
||||
dynamic_class = pytest.mark.__getattr__('module_' + model._meta.app_label)(dynamic_class)
|
||||
|
||||
globals()[cls_name] = dynamic_class
|
@ -41,59 +41,59 @@ router: DefaultRouter = DefaultRouter(trailing_slash=False)
|
||||
|
||||
|
||||
router.register(
|
||||
'history', audit_history.NoDocsViewSet,
|
||||
'/history', audit_history.NoDocsViewSet,
|
||||
basename = '_api_centurionaudit'
|
||||
)
|
||||
|
||||
|
||||
|
||||
router.register(
|
||||
prefix=f'ticket', viewset = ticket.NoDocsViewSet,
|
||||
prefix=f'/ticket', viewset = ticket.NoDocsViewSet,
|
||||
feature_flag = '2025-00006', basename = '_api_ticketbase'
|
||||
)
|
||||
router.register(
|
||||
prefix=f'ticket/(?P<ticket_type>[{ticket_type_names}]+)', viewset = ticket.ViewSet,
|
||||
prefix=f'/ticket/(?P<ticket_type>[{ticket_type_names}]+)', viewset = ticket.ViewSet,
|
||||
feature_flag = '2025-00006', basename = '_api_ticketbase_sub'
|
||||
)
|
||||
router.register(
|
||||
prefix = 'ticket/(?P<ticket_id>[0-9]+)/comment', viewset = ticket_comment.NoDocsViewSet,
|
||||
prefix = '/ticket/(?P<ticket_id>[0-9]+)/comment', viewset = ticket_comment.NoDocsViewSet,
|
||||
feature_flag = '2025-00006', basename = '_api_ticket_comment_base'
|
||||
)
|
||||
router.register(
|
||||
prefix = 'ticket/(?P<ticket_id>[0-9]+)/comment/(?P<parent_id>[0-9]+)/threads',
|
||||
prefix = '/ticket/(?P<ticket_id>[0-9]+)/comment/(?P<parent_id>[0-9]+)/threads',
|
||||
viewset = ticket_comment.ViewSet,
|
||||
feature_flag = '2025-00006', basename = '_api_ticket_comment_base_thread'
|
||||
)
|
||||
router.register(
|
||||
prefix = 'ticket/(?P<ticket_id>[0-9]+)/comments', viewset = ticket_comment_depreciated.ViewSet,
|
||||
prefix = '/ticket/(?P<ticket_id>[0-9]+)/comments', viewset = ticket_comment_depreciated.ViewSet,
|
||||
basename = '_api_v2_ticket_comment'
|
||||
)
|
||||
router.register(
|
||||
prefix = 'ticket/(?P<ticket_id>[0-9]+)/comments/(?P<parent_id>[0-9]+)/threads',
|
||||
prefix = '/ticket/(?P<ticket_id>[0-9]+)/comments/(?P<parent_id>[0-9]+)/threads',
|
||||
viewset = ticket_comment_depreciated.ViewSet,
|
||||
basename = '_api_v2_ticket_comment_threads'
|
||||
)
|
||||
router.register(
|
||||
prefix = 'ticket/(?P<ticket_id>[0-9]+)/linked_item', viewset = ticket_linked_item.ViewSet,
|
||||
prefix = '/ticket/(?P<ticket_id>[0-9]+)/linked_item', viewset = ticket_linked_item.ViewSet,
|
||||
basename = '_api_v2_ticket_linked_item'
|
||||
)
|
||||
router.register(
|
||||
prefix = 'ticket/(?P<ticket_id>[0-9]+)/related_ticket', viewset = related_ticket.ViewSet,
|
||||
prefix = '/ticket/(?P<ticket_id>[0-9]+)/related_ticket', viewset = related_ticket.ViewSet,
|
||||
basename = '_api_v2_ticket_related'
|
||||
)
|
||||
router.register(
|
||||
prefix=f'ticket/(?P<ticket_id>[0-9]+)/(?P<ticket_comment_model>[{ticket_comment_names}]+)',
|
||||
prefix=f'/ticket/(?P<ticket_id>[0-9]+)/(?P<ticket_comment_model>[{ticket_comment_names}]+)',
|
||||
viewset = ticket_comment.ViewSet,
|
||||
feature_flag = '2025-00006', basename = '_api_ticket_comment_base_sub'
|
||||
)
|
||||
router.register(
|
||||
prefix=f'ticket/(?P<ticket_id>[0-9]+)/(?P<ticket_comment_model>[{ticket_comment_names} \
|
||||
prefix=f'/ticket/(?P<ticket_id>[0-9]+)/(?P<ticket_comment_model>[{ticket_comment_names} \
|
||||
]+)/(?P<parent_id>[0-9]+)/threads',
|
||||
viewset = ticket_comment.ViewSet,
|
||||
feature_flag = '2025-00006', basename = '_api_ticket_comment_base_sub_thread'
|
||||
)
|
||||
router.register(
|
||||
prefix = '(?P<item_class>[a-z_]+)/(?P<item_id>[0-9]+)/item_ticket',
|
||||
prefix = '/(?P<item_class>[a-z_]+)/(?P<item_id>[0-9]+)/item_ticket',
|
||||
viewset = ticket_linked_item.ViewSet,
|
||||
basename = '_api_v2_item_tickets'
|
||||
)
|
||||
|
@ -0,0 +1,526 @@
|
||||
# Generated by Django 5.1.10 on 2025-08-15 03:21
|
||||
|
||||
import access.models.tenancy_abstract
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0011_remove_entitynotes_model_and_more"),
|
||||
("core", "0024_centurionaudit_centurionmodelnote_and_more"),
|
||||
("devops", "0012_alter_checkin_organization_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="checkin",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="checkin",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="featureflag",
|
||||
name="description",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Description of this feature",
|
||||
max_length=300,
|
||||
null=True,
|
||||
verbose_name="Description",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="featureflag",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="featureflag",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="featureflag",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="gitgroup",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="gitgroup",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="gitgroup",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="gitgroup",
|
||||
name="parent_group",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="Parent Git Group this repository belongs to.",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="+",
|
||||
to="devops.gitgroup",
|
||||
verbose_name="Parent Group",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="gitrepository",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="gitrepository",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="gitrepository",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="softwareenablefeatureflag",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="softwareenablefeatureflag",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="FeatureFlagAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="devops.featureflag",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Feature Flag History",
|
||||
"verbose_name_plural": "Feature Flag Histories",
|
||||
"db_table": "devops_featureflag_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="FeatureFlagCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="devops.featureflag",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Feature Flag Note",
|
||||
"verbose_name_plural": "Feature Flag Notes",
|
||||
"db_table": "devops_featureflag_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="GitGroupAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="devops.gitgroup",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "GIT Group History",
|
||||
"verbose_name_plural": "GIT Group Histories",
|
||||
"db_table": "devops_gitgroup_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="GitGroupCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="devops.gitgroup",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "GIT Group Note",
|
||||
"verbose_name_plural": "GIT Group Notes",
|
||||
"db_table": "devops_gitgroup_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="GitHubRepositoryAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="devops.githubrepository",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "GitHub Repository History",
|
||||
"verbose_name_plural": "GitHub Repository Histories",
|
||||
"db_table": "devops_githubrepository_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="GitHubRepositoryCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="devops.githubrepository",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "GitHub Repository Note",
|
||||
"verbose_name_plural": "GitHub Repository Notes",
|
||||
"db_table": "devops_githubrepository_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="GitLabRepositoryAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="devops.gitlabrepository",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "GitLab Repository History",
|
||||
"verbose_name_plural": "GitLab Repository Histories",
|
||||
"db_table": "devops_gitlabrepository_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="GitLabRepositoryCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="devops.gitlabrepository",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "GitLab Repository Note",
|
||||
"verbose_name_plural": "GitLab Repository Notes",
|
||||
"db_table": "devops_gitlabrepository_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="GitRepositoryAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="devops.gitrepository",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "GIT Repository History",
|
||||
"verbose_name_plural": "GIT Repository Histories",
|
||||
"db_table": "devops_gitrepository_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="GitRepositoryCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="devops.gitrepository",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "GIT Repository Note",
|
||||
"verbose_name_plural": "GIT Repository Notes",
|
||||
"db_table": "devops_gitrepository_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
]
|
@ -1,46 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-05-24 23:48
|
||||
|
||||
import access.models.tenancy_abstract
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('access', '0010_company_alter_entity_entity_type_alter_person_dob_and_more'),
|
||||
('core', '0026_remove_centurionaudit_model_notes'),
|
||||
('devops', '0012_alter_checkin_organization_and_more'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='gitgroup',
|
||||
name='id',
|
||||
field=models.AutoField(help_text='ID of the item', primary_key=True, serialize=False, unique=True, verbose_name='ID'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='gitgroup',
|
||||
name='model_notes',
|
||||
field=models.TextField(blank=True, help_text='Tid bits of information', null=True, verbose_name='Notes'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='gitgroup',
|
||||
name='organization',
|
||||
field=models.ForeignKey(help_text='Tenant this belongs to', on_delete=django.db.models.deletion.CASCADE, related_name='+', to='access.tenant', validators=[access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists], verbose_name='Tenant'),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='GitGroupAuditHistory',
|
||||
fields=[
|
||||
('centurionaudit_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='core.centurionaudit')),
|
||||
('model', models.ForeignKey(help_text='Model this history belongs to', on_delete=django.db.models.deletion.CASCADE, related_name='audit_history', to='devops.gitgroup', verbose_name='Model')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'GIT Group History',
|
||||
'verbose_name_plural': 'GIT Group Histories',
|
||||
'db_table': 'devops_gitgroup_audithistory',
|
||||
'managed': True,
|
||||
},
|
||||
bases=('core.centurionaudit', models.Model),
|
||||
),
|
||||
]
|
@ -1,27 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-05-29 03:48
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("devops", "0013_alter_gitgroup_id_alter_gitgroup_model_notes_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="gitgroup",
|
||||
name="parent_group",
|
||||
field=models.ForeignKey(
|
||||
blank=True,
|
||||
help_text="Parent Git Group this repository belongs to.",
|
||||
null=True,
|
||||
on_delete=django.db.models.deletion.PROTECT,
|
||||
related_name="+",
|
||||
to="devops.gitgroup",
|
||||
verbose_name="Parent Group",
|
||||
),
|
||||
),
|
||||
]
|
@ -1,48 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-05-29 19:49
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("core", "0027_centurionmodelnote"),
|
||||
("devops", "0014_alter_gitgroup_parent_group"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="GitGroupCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="devops.gitgroup",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "GIT Group Note",
|
||||
"verbose_name_plural": "GIT Group Notes",
|
||||
"db_table": "devops_gitgroup_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote", models.Model),
|
||||
),
|
||||
]
|
@ -1,129 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-05-30 19:28
|
||||
|
||||
import access.models.tenancy_abstract
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0010_company_alter_entity_entity_type_alter_person_dob_and_more"),
|
||||
("core", "0027_centurionmodelnote"),
|
||||
("devops", "0015_gitgroupcenturionmodelnote"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="featureflag",
|
||||
name="description",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Description of this feature",
|
||||
max_length=300,
|
||||
null=True,
|
||||
verbose_name="Description",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="featureflag",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="featureflag",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="featureflag",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="FeatureFlagAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="devops.featureflag",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Feature Flag History",
|
||||
"verbose_name_plural": "Feature Flag Histories",
|
||||
"db_table": "devops_featureflag_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit", models.Model),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="FeatureFlagCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="devops.featureflag",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "Feature Flag Note",
|
||||
"verbose_name_plural": "Feature Flag Notes",
|
||||
"db_table": "devops_featureflag_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote", models.Model),
|
||||
),
|
||||
]
|
@ -1,41 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-09 01:01
|
||||
|
||||
import access.models.tenancy_abstract
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0016_remove_tenant_slug_alter_tenant_manager_and_more"),
|
||||
("devops", "0016_alter_featureflag_description_alter_featureflag_id_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="checkin",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="checkin",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
]
|
@ -1,118 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-09 07:20
|
||||
|
||||
import access.models.tenancy_abstract
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0016_remove_tenant_slug_alter_tenant_manager_and_more"),
|
||||
("core", "0033_alter_ticketcommentcategory_parent_and_more"),
|
||||
("devops", "0017_alter_checkin_id_alter_checkin_organization"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="gitrepository",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="gitrepository",
|
||||
name="model_notes",
|
||||
field=models.TextField(
|
||||
blank=True,
|
||||
help_text="Tid bits of information",
|
||||
null=True,
|
||||
verbose_name="Notes",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="gitrepository",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="GitRepositoryAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="audit_history",
|
||||
to="devops.gitrepository",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "GIT Repository History",
|
||||
"verbose_name_plural": "GIT Repository Histories",
|
||||
"db_table": "devops_gitrepository_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="GitRepositoryCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="devops.gitrepository",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "GIT Repository Note",
|
||||
"verbose_name_plural": "GIT Repository Notes",
|
||||
"db_table": "devops_gitrepository_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
]
|
@ -1,81 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-09 07:21
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("core", "0033_alter_ticketcommentcategory_parent_and_more"),
|
||||
("devops", "0018_gitrepositoryaudithistory_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="GitHubRepositoryAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="devops.githubrepository",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "GitHub Repository History",
|
||||
"verbose_name_plural": "GitHub Repository Histories",
|
||||
"db_table": "devops_githubrepository_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="GitHubRepositoryCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="devops.githubrepository",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "GitHub Repository Note",
|
||||
"verbose_name_plural": "GitHub Repository Notes",
|
||||
"db_table": "devops_githubrepository_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
)
|
||||
]
|
@ -1,81 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-09 07:25
|
||||
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("core", "0033_alter_ticketcommentcategory_parent_and_more"),
|
||||
("devops", "0019_githubrepositoryaudithistory_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name="GitLabRepositoryAuditHistory",
|
||||
fields=[
|
||||
(
|
||||
"centurionaudit_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionaudit",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this history belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="devops.gitlabrepository",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "GitLab Repository History",
|
||||
"verbose_name_plural": "GitLab Repository Histories",
|
||||
"db_table": "devops_gitlabrepository_audithistory",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionaudit",),
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name="GitLabRepositoryCenturionModelNote",
|
||||
fields=[
|
||||
(
|
||||
"centurionmodelnote_ptr",
|
||||
models.OneToOneField(
|
||||
auto_created=True,
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
parent_link=True,
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
to="core.centurionmodelnote",
|
||||
),
|
||||
),
|
||||
(
|
||||
"model",
|
||||
models.ForeignKey(
|
||||
help_text="Model this note belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="devops.gitlabrepository",
|
||||
verbose_name="Model",
|
||||
),
|
||||
),
|
||||
],
|
||||
options={
|
||||
"verbose_name": "GitLab Repository Note",
|
||||
"verbose_name_plural": "GitLab Repository Notes",
|
||||
"db_table": "devops_gitlabrepository_centurionmodelnote",
|
||||
"managed": True,
|
||||
},
|
||||
bases=("core.centurionmodelnote",),
|
||||
),
|
||||
]
|
@ -1,41 +0,0 @@
|
||||
# Generated by Django 5.1.9 on 2025-06-11 05:39
|
||||
|
||||
import access.models.tenancy_abstract
|
||||
import django.db.models.deletion
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
("access", "0016_remove_tenant_slug_alter_tenant_manager_and_more"),
|
||||
("devops", "0020_gitlabrepositoryaudithistory_and_more"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name="softwareenablefeatureflag",
|
||||
name="id",
|
||||
field=models.AutoField(
|
||||
help_text="ID of the item",
|
||||
primary_key=True,
|
||||
serialize=False,
|
||||
unique=True,
|
||||
verbose_name="ID",
|
||||
),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name="softwareenablefeatureflag",
|
||||
name="organization",
|
||||
field=models.ForeignKey(
|
||||
help_text="Tenant this belongs to",
|
||||
on_delete=django.db.models.deletion.CASCADE,
|
||||
related_name="+",
|
||||
to="access.tenant",
|
||||
validators=[
|
||||
access.models.tenancy_abstract.TenancyAbstractModel.validatate_organization_exists
|
||||
],
|
||||
verbose_name="Tenant",
|
||||
),
|
||||
),
|
||||
]
|
26
app/devops/tests/functional/feature_flag/conftest.py
Normal file
26
app/devops/tests/functional/feature_flag/conftest.py
Normal file
@ -0,0 +1,26 @@
|
||||
import pytest
|
||||
|
||||
|
||||
|
||||
|
||||
@pytest.fixture( scope = 'class')
|
||||
def model(model_featureflag):
|
||||
|
||||
yield model_featureflag
|
||||
|
||||
|
||||
@pytest.fixture( scope = 'class', autouse = True)
|
||||
def model_kwargs(request, kwargs_featureflag):
|
||||
|
||||
request.cls.kwargs_create_item = kwargs_featureflag.copy()
|
||||
|
||||
yield kwargs_featureflag.copy()
|
||||
|
||||
if hasattr(request.cls, 'kwargs_create_item'):
|
||||
del request.cls.kwargs_create_item
|
||||
|
||||
|
||||
@pytest.fixture( scope = 'class')
|
||||
def model_serializer(serializer_featureflag):
|
||||
|
||||
yield serializer_featureflag
|
@ -1,213 +0,0 @@
|
||||
import pytest
|
||||
|
||||
from django.test import TestCase
|
||||
|
||||
from rest_framework.exceptions import ValidationError
|
||||
|
||||
from access.models.tenant import Tenant as Organization
|
||||
|
||||
from devops.models.software_enable_feature_flag import SoftwareEnableFeatureFlag
|
||||
from devops.serializers.feature_flag import FeatureFlag, ModelSerializer
|
||||
|
||||
from itam.models.software import Software
|
||||
|
||||
|
||||
|
||||
class ValidationAPI(
|
||||
TestCase,
|
||||
):
|
||||
|
||||
model = FeatureFlag
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(self):
|
||||
"""Setup Test
|
||||
|
||||
1. Create an org
|
||||
2. Create an item
|
||||
"""
|
||||
|
||||
organization = Organization.objects.create(name='test_org')
|
||||
|
||||
self.organization = organization
|
||||
|
||||
self.diff_organization = Organization.objects.create(name='test_org_diff_org')
|
||||
|
||||
software = Software.objects.create(
|
||||
organization = self.organization,
|
||||
name = 'soft',
|
||||
)
|
||||
|
||||
SoftwareEnableFeatureFlag.objects.create(
|
||||
organization = self.organization,
|
||||
software = software,
|
||||
enabled = True
|
||||
)
|
||||
|
||||
self.item = self.model.objects.create(
|
||||
organization = self.organization,
|
||||
name = 'one',
|
||||
software = software,
|
||||
description = 'desc',
|
||||
model_notes = 'text',
|
||||
enabled = True
|
||||
)
|
||||
|
||||
self.valid_data = {
|
||||
'organization': self.organization.id,
|
||||
'name': 'two',
|
||||
'software': software.id,
|
||||
'description': 'a description',
|
||||
'model_notes': 'dfsdfsd',
|
||||
'enabled': True
|
||||
}
|
||||
|
||||
|
||||
self.software_no_feature_flag_enabled = Software.objects.create(
|
||||
organization = self.organization,
|
||||
name = 'soft no flagging',
|
||||
)
|
||||
|
||||
|
||||
|
||||
def test_serializer_validation_valid_data(self):
|
||||
"""Serializer Validation Check
|
||||
|
||||
Ensure that if creating and no name is provided a validation error occurs
|
||||
"""
|
||||
|
||||
serializer = ModelSerializer(
|
||||
data = self.valid_data
|
||||
)
|
||||
|
||||
|
||||
assert serializer.is_valid( raise_exception = True )
|
||||
|
||||
|
||||
def test_serializer_validation_no_name_exception(self):
|
||||
"""Serializer Validation Check
|
||||
|
||||
Ensure that when creating and field name is not provided a
|
||||
validation error occurs
|
||||
"""
|
||||
|
||||
valid_data = self.valid_data.copy()
|
||||
|
||||
del valid_data['name']
|
||||
|
||||
with pytest.raises(ValidationError) as err:
|
||||
|
||||
serializer = ModelSerializer(
|
||||
data = valid_data
|
||||
)
|
||||
|
||||
serializer.is_valid(raise_exception = True)
|
||||
|
||||
assert err.value.get_codes()['name'][0] == 'required'
|
||||
|
||||
|
||||
def test_serializer_validation_no_software_exception(self):
|
||||
"""Serializer Validation Check
|
||||
|
||||
Ensure that when creating and field software is not provided, no
|
||||
validation error occurs
|
||||
"""
|
||||
|
||||
valid_data = self.valid_data.copy()
|
||||
|
||||
del valid_data['software']
|
||||
|
||||
with pytest.raises(ValidationError) as err:
|
||||
|
||||
serializer = ModelSerializer(
|
||||
data = valid_data
|
||||
)
|
||||
|
||||
serializer.is_valid(raise_exception = True)
|
||||
|
||||
assert err.value.get_codes()['software'][0] == 'required'
|
||||
|
||||
|
||||
def test_serializer_validation_feature_flagging_not_enabled(self):
|
||||
"""Serializer Validation Check
|
||||
|
||||
Ensure that when creating and the software doesn't, have feature
|
||||
flagging enabled an exception is thrown.
|
||||
"""
|
||||
|
||||
valid_data = self.valid_data.copy()
|
||||
|
||||
valid_data['software'] = self.software_no_feature_flag_enabled.id
|
||||
|
||||
with pytest.raises(ValidationError) as err:
|
||||
|
||||
serializer = ModelSerializer(
|
||||
data = valid_data
|
||||
)
|
||||
|
||||
serializer.is_valid(raise_exception = True)
|
||||
|
||||
assert err.value.get_codes()['software'] == 'feature_flagging_disabled'
|
||||
|
||||
|
||||
def test_serializer_validation_feature_flagging_not_enabled_for_organization(self):
|
||||
"""Serializer Validation Check
|
||||
|
||||
Ensure that when creating and the software doesn't, have feature
|
||||
flagging enabled an exception is thrown.
|
||||
"""
|
||||
|
||||
valid_data = self.valid_data.copy()
|
||||
|
||||
valid_data['organization'] = self.diff_organization.id
|
||||
|
||||
with pytest.raises(ValidationError) as err:
|
||||
|
||||
serializer = ModelSerializer(
|
||||
data = valid_data
|
||||
)
|
||||
|
||||
serializer.is_valid(raise_exception = True)
|
||||
|
||||
assert err.value.get_codes()['organization'] == 'feature_flagging_wrong_organizaiton'
|
||||
|
||||
|
||||
|
||||
def test_serializer_validation_no_description_ok(self):
|
||||
"""Serializer Validation Check
|
||||
|
||||
Ensure that when creating and field description is not provided, no
|
||||
validation error occurs
|
||||
"""
|
||||
|
||||
valid_data = self.valid_data.copy()
|
||||
|
||||
del valid_data['description']
|
||||
|
||||
serializer = ModelSerializer(
|
||||
data = valid_data
|
||||
)
|
||||
|
||||
assert serializer.is_valid(raise_exception = True)
|
||||
|
||||
|
||||
def test_serializer_validation_no_enabled_ok_default_false(self):
|
||||
"""Serializer Validation Check
|
||||
|
||||
Ensure that when creating and field enabled is not provided, no
|
||||
validation error occurs and enabled is set to `false`
|
||||
"""
|
||||
|
||||
valid_data = self.valid_data.copy()
|
||||
|
||||
del valid_data['enabled']
|
||||
|
||||
serializer = ModelSerializer(
|
||||
data = valid_data
|
||||
)
|
||||
|
||||
assert serializer.is_valid(raise_exception = True)
|
||||
|
||||
serializer.save()
|
||||
|
||||
assert serializer.instance.enabled is False
|
@ -0,0 +1,134 @@
|
||||
import pytest
|
||||
|
||||
from django.db import models
|
||||
|
||||
from rest_framework.relations import Hyperlink
|
||||
|
||||
from api.tests.functional.test_functional_api_fields import (
|
||||
APIFieldsInheritedCases,
|
||||
)
|
||||
|
||||
|
||||
|
||||
@pytest.mark.model_featureflag
|
||||
class FeatureFlagAPITestCases(
|
||||
APIFieldsInheritedCases,
|
||||
):
|
||||
|
||||
# @pytest.fixture( scope = 'class')
|
||||
# def second_model(self, request, django_db_blocker,
|
||||
# model, model_kwargs
|
||||
# ):
|
||||
|
||||
# item = None
|
||||
|
||||
# with django_db_blocker.unblock():
|
||||
|
||||
# kwargs_many_to_many = {}
|
||||
|
||||
# kwargs = {}
|
||||
|
||||
# for key, value in model_kwargs.items():
|
||||
|
||||
# field = model._meta.get_field(key)
|
||||
|
||||
# if isinstance(field, models.ManyToManyField):
|
||||
|
||||
# kwargs_many_to_many.update({
|
||||
# key: value
|
||||
# })
|
||||
|
||||
# else:
|
||||
|
||||
# kwargs.update({
|
||||
# key: value
|
||||
# })
|
||||
|
||||
|
||||
# # Switch model fields so all fields can be checked
|
||||
# kwargs_many_to_many.update({ 'responsible_teams': kwargs_many_to_many['target_team']})
|
||||
# del kwargs_many_to_many['target_team']
|
||||
|
||||
# kwargs.update({ 'target_user': kwargs['responsible_user']})
|
||||
# del kwargs['responsible_user']
|
||||
|
||||
|
||||
# item_two = model.objects.create(
|
||||
# **kwargs
|
||||
# )
|
||||
|
||||
|
||||
# for key, value in kwargs_many_to_many.items():
|
||||
|
||||
# field = getattr(item_two, key)
|
||||
|
||||
# for entry in value:
|
||||
|
||||
# field.add(entry)
|
||||
|
||||
|
||||
# request.cls.item_two = item_two
|
||||
|
||||
# yield item_two
|
||||
|
||||
# with django_db_blocker.unblock():
|
||||
|
||||
# item_two.delete()
|
||||
|
||||
# del request.cls.item_two
|
||||
|
||||
|
||||
# @pytest.fixture( scope = 'class', autouse = True)
|
||||
# def class_setup(self,
|
||||
# create_model,
|
||||
# second_model,
|
||||
# make_request,
|
||||
# ):
|
||||
|
||||
# pass
|
||||
|
||||
@property
|
||||
def parameterized_api_fields(self):
|
||||
|
||||
return {
|
||||
'software': {
|
||||
'expected': dict
|
||||
},
|
||||
'software.id': {
|
||||
'expected': int
|
||||
},
|
||||
'software.display_name': {
|
||||
'expected': str
|
||||
},
|
||||
'software.url': {
|
||||
'expected': Hyperlink
|
||||
},
|
||||
'name': {
|
||||
'expected': str
|
||||
},
|
||||
'description': {
|
||||
'expected': str
|
||||
},
|
||||
'enabled': {
|
||||
'expected': bool
|
||||
},
|
||||
'modified': {
|
||||
'expected': str
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class FeatureFlagAPIInheritedCases(
|
||||
FeatureFlagAPITestCases,
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@pytest.mark.module_devops
|
||||
class FeatureFlagAPIPyTest(
|
||||
FeatureFlagAPITestCases,
|
||||
):
|
||||
|
||||
pass
|
@ -0,0 +1,28 @@
|
||||
import pytest
|
||||
|
||||
from core.tests.functional.centurion_abstract.test_functional_centurion_abstract_model import (
|
||||
CenturionAbstractModelInheritedCases
|
||||
)
|
||||
|
||||
|
||||
|
||||
@pytest.mark.model_featureflag
|
||||
class FeatureFlagModelTestCases(
|
||||
CenturionAbstractModelInheritedCases
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
class FeatureFlagModelInheritedCases(
|
||||
FeatureFlagModelTestCases,
|
||||
):
|
||||
pass
|
||||
|
||||
|
||||
|
||||
@pytest.mark.module_devops
|
||||
class FeatureFlagModelPyTest(
|
||||
FeatureFlagModelTestCases,
|
||||
):
|
||||
pass
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user