Skip to content

Commit

Permalink
Merge pull request #446 from nofusscomputing/development
Browse files Browse the repository at this point in the history
  • Loading branch information
jon-nfc authored Dec 23, 2024
2 parents e982d65 + 1df7499 commit bc16498
Show file tree
Hide file tree
Showing 88 changed files with 2,555 additions and 88 deletions.
1 change: 1 addition & 0 deletions app/access/functions/permissions.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ def permission_queryset():
'django_celery_results',
'itam',
'itim',
'project_management',
'settings',
]

Expand Down
22 changes: 22 additions & 0 deletions app/access/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,16 @@ def __str__(self):
}
]
},
{
"name": "Knowledge Base",
"slug": "kb_articles",
"sections": [
{
"layout": "table",
"field": "knowledge_base",
}
]
},
{
"name": "Notes",
"slug": "notes",
Expand Down Expand Up @@ -311,6 +321,8 @@ def get_url_kwargs(self) -> dict:

def save(self, force_insert=False, force_update=False, using=None, update_fields=None):

self.clean()

if self.organization is None:

raise ValidationError('Organization not defined')
Expand Down Expand Up @@ -373,6 +385,16 @@ def save(self, force_insert=False, force_update=False, using=None, update_fields
},
]
},
{
"name": "Knowledge Base",
"slug": "kb_articles",
"sections": [
{
"layout": "table",
"field": "knowledge_base",
}
]
},
{
"name": "Notes",
"slug": "notes",
Expand Down
8 changes: 8 additions & 0 deletions app/access/serializers/organization.py
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,14 @@ def get_url(self, item) -> dict:

return {
'_self': item.get_url( request = self._context['view'].request ),
'knowledge_base': reverse(
"v2:_api_v2_model_kb-list",
request=self._context['view'].request,
kwargs={
'model': self.Meta.model._meta.model_name,
'model_pk': item.pk
}
),
'teams': reverse("v2:_api_v2_organization_team-list", request=self._context['view'].request, kwargs={'organization_id': item.pk}),
}

Expand Down
8 changes: 8 additions & 0 deletions app/access/serializers/teams.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,14 @@ def get_url(self, item) -> dict:

return {
'_self': item.get_url( request = self._context['view'].request ),
'knowledge_base': reverse(
"v2:_api_v2_model_kb-list",
request=self._context['view'].request,
kwargs={
'model': self.Meta.model._meta.model_name,
'model_pk': item.pk
}
),
'users': reverse(
'v2:_api_v2_organization_team_user-list',
request=self.context['view'].request,
Expand Down
14 changes: 14 additions & 0 deletions app/access/tests/unit/team_user/test_team_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

from app.tests.abstract.models import BaseModel

from core.mixin.history_save import SaveHistory



class TeamUsersModel(
TestCase,
Expand Down Expand Up @@ -58,3 +61,14 @@ def test_model_property_parent_object_returns_object(self):
"""

assert self.item.parent_object == self.parent_item



@pytest.mark.skip( reason = 'TeamUsers is not a tenancy object' )
def test_class_inherits_tenancy_objecy(self):
""" Confirm class inheritence
TenancyObject must inherit TenancyObject
"""

pass
21 changes: 21 additions & 0 deletions app/api/react_ui_metadata.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

from rest_framework_json_api.utils import get_related_resource_type

from access.models import Organization

from app.serializers.user import User, UserBaseSerializer

from core import fields as centurion_field
Expand Down Expand Up @@ -450,6 +452,14 @@ def get_navigation(self, user) -> list(dict()):
'settings.view_appsettings',
]


# user = view.request.user

user_orgainzations = Organization.objects.filter(
manager = user
)


for app, entry in self._nav.items():

new_menu_entry: dict = {}
Expand Down Expand Up @@ -494,6 +504,17 @@ def get_navigation(self, user) -> list(dict()):
new_pages += [ page ]


if(
app == 'access'
and permission == 'view_organization'
and len(user_orgainzations) > 0
):

if page not in new_pages:

new_pages += [ page ]


if len(new_pages) > 0:

new_menu_entry = entry.copy()
Expand Down
16 changes: 8 additions & 8 deletions app/api/tests/abstract/api_permissions_viewset.py
Original file line number Diff line number Diff line change
Expand Up @@ -468,36 +468,36 @@ def test_delete_permission_add_denied(self):
assert response.status_code == 403


def test_delete_permission_change_denied(self):
def test_delete_has_permission(self):
""" Check correct permission for delete
Attempt to delete as user with change permission only
Delete item as user with delete permission
"""

client = Client()
url = reverse(self.app_namespace + ':' + self.url_name + '-detail', kwargs=self.url_view_kwargs)


client.force_login(self.change_user)
client.force_login(self.delete_user)
response = client.delete(url, data=self.delete_data)

assert response.status_code == 403
assert response.status_code == 204


def test_delete_has_permission(self):
def test_delete_permission_change_denied(self):
""" Check correct permission for delete
Delete item as user with delete permission
Attempt to delete as user with change permission only
"""

client = Client()
url = reverse(self.app_namespace + ':' + self.url_name + '-detail', kwargs=self.url_view_kwargs)


client.force_login(self.delete_user)
client.force_login(self.change_user)
response = client.delete(url, data=self.delete_data)

assert response.status_code == 204
assert response.status_code == 403



Expand Down
2 changes: 2 additions & 0 deletions app/api/urls_v2.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
index as assistance_index_v2,
knowledge_base as knowledge_base_v2,
knowledge_base_category as knowledge_base_category_v2,
model_knowledge_base_article,
request as request_ticket_v2,
)

Expand Down Expand Up @@ -107,6 +108,7 @@

router.register('assistance', assistance_index_v2.Index, basename='_api_v2_assistance_home')
router.register('assistance/knowledge_base', knowledge_base_v2.ViewSet, basename='_api_v2_knowledge_base')
router.register('assistance/(?P<model>.+)/(?P<model_pk>[0-9]+)/knowledge_base', model_knowledge_base_article.ViewSet, basename='_api_v2_model_kb')
router.register('assistance/ticket/request', request_ticket_v2.ViewSet, basename='_api_v2_ticket_request')


Expand Down
61 changes: 56 additions & 5 deletions app/api/views/mixin.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,12 +15,32 @@ class OrganizationPermissionAPI(DjangoObjectPermissions, OrganizationMixin):

def has_permission(self, request, view):

# if view.kwargs.get('pk', None):

# if(
# str(type(view.get_object()).__name__).lower() == 'organization'
# ):

# if view.get_object().manager == request.user:

# return True

return self.permission_check(request, view)


def has_object_permission(self, request, view, obj):

return self.permission_check(request, view, obj)
# if view.kwargs.get('pk', None):

# if(
# str(type(obj).__name__).lower() == 'organization'
# ):

# if obj.manager == request.user:

# return True

return self.permission_check(request, view)


def permission_check(self, request, view, obj=None) -> bool:
Expand Down Expand Up @@ -67,10 +87,34 @@ def permission_check(self, request, view, obj=None) -> bool:

if 'organization' in request.data:

if not request.data['organization']:
raise centurion_exceptions.ValidationError('you must provide an organization')
serializer = None

try: # Method throws exception if not overridden

serializer = view.get_serializer_class()

except Exception as e:

serializer = None

try: # Method throws exception if not overridden

serializer = view.get_serializer()

except Exception as e:

serializer = None


if 'organization' not in getattr(serializer.Meta, 'read_only_fields', []):

if not request.data['organization']:

raise centurion_exceptions.ValidationError('you must provide an organization')

object_organization = int(request.data['organization'])


object_organization = int(request.data['organization'])
elif method == 'patch':

action = 'change'
Expand All @@ -88,7 +132,7 @@ def permission_check(self, request, view, obj=None) -> bool:
action = 'view'

if hasattr(self, 'obj'):

permission = self.obj._meta.app_label + '.' + action + '_' + self.obj._meta.model_name

self.permission_required = [ permission ]
Expand Down Expand Up @@ -116,6 +160,13 @@ def permission_check(self, request, view, obj=None) -> bool:
return False


if object_organization is None and getattr(view, 'parent_model', None):

parent_model = view.parent_model.objects.get(pk=view.kwargs[view.parent_model_pk_kwarg])

object_organization = parent_model.organization.id


if obj:

if obj.get_organization():
Expand Down
12 changes: 11 additions & 1 deletion app/app/tests/abstract/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,23 @@ class BaseModel:
""" Model to test """


@pytest.mark.skip(reason="figure out how to test sub-sub-class")

def test_class_inherits_save_history(self):
""" Confirm class inheritence
TenancyObject must inherit SaveHistory
"""

assert issubclass(self.model, SaveHistory)



def test_class_inherits_tenancy_objecy(self):
""" Confirm class inheritence
TenancyObject must inherit TenancyObject
"""

assert issubclass(self.model, TenancyObject)


Expand Down
39 changes: 39 additions & 0 deletions app/assistance/migrations/0003_modelknowledgebasearticle.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
# Generated by Django 5.1.4 on 2024-12-20 08:34

import access.fields
import access.models
import assistance.models.model_knowledge_base_article
import django.db.models.deletion
import django.utils.timezone
from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('access', '0002_alter_organization_options_alter_team_options_and_more'),
('assistance', '0002_alter_knowledgebase_options_and_more'),
]

operations = [
migrations.CreateModel(
name='ModelKnowledgeBaseArticle',
fields=[
('is_global', models.BooleanField(default=False, help_text='Is this a global object?', verbose_name='Global Object')),
('id', models.AutoField(help_text='ID of this KB article link', primary_key=True, serialize=False, unique=True, verbose_name='ID')),
('model', models.CharField(choices=assistance.models.model_knowledge_base_article.all_models, help_text='Model type to link to article article', max_length=50, verbose_name='Model Type')),
('model_pk', models.IntegerField(help_text='PK of the model the article is linked to', verbose_name='Model Primary Key')),
('created', access.fields.AutoCreatedField(default=django.utils.timezone.now, editable=False, help_text='Date and time of creation', verbose_name='Created')),
('modified', access.fields.AutoLastModifiedField(default=django.utils.timezone.now, editable=False, help_text='Date and time of last modification', verbose_name='Modified')),
('article', models.ForeignKey(help_text='Article to be linked to model', on_delete=django.db.models.deletion.CASCADE, to='assistance.knowledgebase', verbose_name='Article')),
('organization', models.ForeignKey(help_text='Organization this belongs to', on_delete=django.db.models.deletion.CASCADE, to='access.organization', validators=[access.models.TenancyObject.validatate_organization_exists], verbose_name='Organization')),
],
options={
'verbose_name': 'Model Knowledge Base Article',
'verbose_name_plural': 'Model Knowledge Base Articles',
'ordering': ['model', 'id'],
'default_permissions': ('add', 'delete', 'view'),
'unique_together': {('article', 'model', 'model_pk')},
},
),
]
12 changes: 0 additions & 12 deletions app/assistance/models/knowledge_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -291,18 +291,6 @@ class Meta:
'target_user',
'target_team',
]
},
{
"layout": "single",
"fields": [
'summary',
]
},
{
"layout": "single",
"fields": [
'content',
]
}
]
},
Expand Down
Loading

0 comments on commit bc16498

Please sign in to comment.