mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-04-23 10:17:14 +00:00
Compare commits
5 Commits
12c4b63947
...
5174a442bc
| Author | SHA1 | Date | |
|---|---|---|---|
| 5174a442bc | |||
| 5f1fd59dd2 | |||
| 3be2a9f4b5 | |||
| 883ef4ed8b | |||
| 2195a60438 |
18
.github/workflows/django.yml
vendored
18
.github/workflows/django.yml
vendored
@@ -14,13 +14,7 @@ jobs:
|
|||||||
if: "!contains(github.event.head_commit.message, '[ci skip]')"
|
if: "!contains(github.event.head_commit.message, '[ci skip]')"
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
test-group: ["RIGS.tests.test_unit RIGS.tests.test_models RIGS.tests.test_functional", "versioning.tests.test_versioning", "users.tests.test_users"]
|
test-group: ["RIGS", "versioning", "users", "assets"]
|
||||||
parallel: [true]
|
|
||||||
include:
|
|
||||||
- test-group: "assets.tests.test_assets"
|
|
||||||
parallel: false
|
|
||||||
- test-group: "RIGS.tests.test_interaction"
|
|
||||||
parallel: false
|
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- name: Set up Python
|
- name: Set up Python
|
||||||
@@ -52,19 +46,15 @@ jobs:
|
|||||||
python manage.py check
|
python manage.py check
|
||||||
python manage.py makemigrations --check --dry-run
|
python manage.py makemigrations --check --dry-run
|
||||||
- name: Run Tests
|
- name: Run Tests
|
||||||
if: \!${{ matrix.parallel }}
|
run: coverage run -p -m pytest --cov=${{ matrix.test-group }} --cov-append -n 8 ${{ matrix.test-group }}/tests/
|
||||||
run: coverage run manage.py test ${{ matrix.test-group }} --verbosity=2
|
|
||||||
- uses: actions/upload-artifact@v2
|
- uses: actions/upload-artifact@v2
|
||||||
if: failure() # Screenshots only make sense for the non-parallel, i.e. interaction tests anyway
|
if: failure()
|
||||||
with:
|
with:
|
||||||
name: failure-screenshots ${{ matrix.test-group }}
|
name: failure-screenshots ${{ matrix.test-group }}
|
||||||
path: screenshots/
|
path: screenshots/
|
||||||
retention-days: 5
|
retention-days: 5
|
||||||
- name: Run Tests (Parallel)
|
|
||||||
if: ${{ matrix.parallel }}
|
|
||||||
run: coverage run manage.py test ${{ matrix.test-group }} --parallel --verbosity=2
|
|
||||||
- name: Upload Coverage
|
- name: Upload Coverage
|
||||||
run: coveralls --service=github
|
run: coverage combine && coveralls --service=github
|
||||||
env:
|
env:
|
||||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
COVERALLS_FLAG_NAME: ${{ matrix.test-group }}
|
COVERALLS_FLAG_NAME: ${{ matrix.test-group }}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
from django.urls import path
|
from django.urls import path, re_path
|
||||||
from django.conf.urls import include, url
|
from django.conf.urls import include
|
||||||
from django.contrib import admin
|
from django.contrib import admin
|
||||||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
@@ -39,6 +39,6 @@ if settings.DEBUG:
|
|||||||
|
|
||||||
import debug_toolbar
|
import debug_toolbar
|
||||||
urlpatterns = [
|
urlpatterns = [
|
||||||
url(r'^__debug__/', include(debug_toolbar.urls)),
|
re_path(r'^__debug__/', include(debug_toolbar.urls)),
|
||||||
path('bootstrap/', TemplateView.as_view(template_name="bootstrap.html")),
|
path('bootstrap/', TemplateView.as_view(template_name="bootstrap.html")),
|
||||||
] + urlpatterns
|
] + urlpatterns
|
||||||
|
|||||||
@@ -24,7 +24,12 @@ from django.views.decorators.cache import never_cache, cache_page
|
|||||||
from django.utils.decorators import method_decorator
|
from django.utils.decorators import method_decorator
|
||||||
|
|
||||||
|
|
||||||
|
def is_ajax(request):
|
||||||
|
return request.headers.get('x-requested-with') == 'XMLHttpRequest'
|
||||||
|
|
||||||
# Displays the current rig count along with a few other bits and pieces
|
# Displays the current rig count along with a few other bits and pieces
|
||||||
|
|
||||||
|
|
||||||
class Index(generic.TemplateView):
|
class Index(generic.TemplateView):
|
||||||
template_name = 'index.html'
|
template_name = 'index.html'
|
||||||
|
|
||||||
@@ -151,7 +156,7 @@ class SecureAPIRequest(generic.View):
|
|||||||
|
|
||||||
class ModalURLMixin:
|
class ModalURLMixin:
|
||||||
def get_close_url(self, update, detail):
|
def get_close_url(self, update, detail):
|
||||||
if self.request.is_ajax():
|
if is_ajax(self.request):
|
||||||
url = reverse_lazy('closemodal')
|
url = reverse_lazy('closemodal')
|
||||||
update_url = str(reverse_lazy(update, kwargs={'pk': self.object.pk}))
|
update_url = str(reverse_lazy(update, kwargs={'pk': self.object.pk}))
|
||||||
messages.info(self.request, "modalobject=" + serializers.serialize("json", [self.object]))
|
messages.info(self.request, "modalobject=" + serializers.serialize("json", [self.object]))
|
||||||
@@ -170,7 +175,7 @@ class GenericListView(generic.ListView):
|
|||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(GenericListView, self).get_context_data(**kwargs)
|
context = super(GenericListView, self).get_context_data(**kwargs)
|
||||||
context['page_title'] = self.model.__name__ + "s"
|
context['page_title'] = self.model.__name__ + "s"
|
||||||
if self.request.is_ajax():
|
if is_ajax(self.request):
|
||||||
context['override'] = "base_ajax.html"
|
context['override'] = "base_ajax.html"
|
||||||
return context
|
return context
|
||||||
|
|
||||||
@@ -202,7 +207,7 @@ class GenericDetailView(generic.DetailView):
|
|||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(GenericDetailView, self).get_context_data(**kwargs)
|
context = super(GenericDetailView, self).get_context_data(**kwargs)
|
||||||
context['page_title'] = "{} | {}".format(self.model.__name__, self.object.name)
|
context['page_title'] = "{} | {}".format(self.model.__name__, self.object.name)
|
||||||
if self.request.is_ajax():
|
if is_ajax(self.request):
|
||||||
context['override'] = "base_ajax.html"
|
context['override'] = "base_ajax.html"
|
||||||
return context
|
return context
|
||||||
|
|
||||||
@@ -213,7 +218,7 @@ class GenericUpdateView(generic.UpdateView):
|
|||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(GenericUpdateView, self).get_context_data(**kwargs)
|
context = super(GenericUpdateView, self).get_context_data(**kwargs)
|
||||||
context['page_title'] = "Edit {}".format(self.model.__name__)
|
context['page_title'] = "Edit {}".format(self.model.__name__)
|
||||||
if self.request.is_ajax():
|
if is_ajax(self.request):
|
||||||
context['override'] = "base_ajax.html"
|
context['override'] = "base_ajax.html"
|
||||||
return context
|
return context
|
||||||
|
|
||||||
@@ -224,7 +229,7 @@ class GenericCreateView(generic.CreateView):
|
|||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(GenericCreateView, self).get_context_data(**kwargs)
|
context = super(GenericCreateView, self).get_context_data(**kwargs)
|
||||||
context['page_title'] = "Create {}".format(self.model.__name__)
|
context['page_title'] = "Create {}".format(self.model.__name__)
|
||||||
if self.request.is_ajax():
|
if is_ajax(self.request):
|
||||||
context['override'] = "base_ajax.html"
|
context['override'] = "base_ajax.html"
|
||||||
return context
|
return context
|
||||||
|
|
||||||
|
|||||||
10
RIGS/urls.py
10
RIGS/urls.py
@@ -1,6 +1,6 @@
|
|||||||
from django.conf.urls import url
|
from django.conf.urls import url
|
||||||
from django.contrib.auth.decorators import login_required
|
from django.contrib.auth.decorators import login_required
|
||||||
from django.urls import path
|
from django.urls import path, re_path
|
||||||
from django.views.decorators.clickjacking import xframe_options_exempt
|
from django.views.decorators.clickjacking import xframe_options_exempt
|
||||||
from django.views.generic import RedirectView
|
from django.views.generic import RedirectView
|
||||||
from PyRIGS.decorators import (api_key_required, has_oembed,
|
from PyRIGS.decorators import (api_key_required, has_oembed,
|
||||||
@@ -45,9 +45,9 @@ urlpatterns = [
|
|||||||
path('rigboard/', login_required(rigboard.RigboardIndex.as_view()), name='rigboard'),
|
path('rigboard/', login_required(rigboard.RigboardIndex.as_view()), name='rigboard'),
|
||||||
path('rigboard/calendar/', login_required()(rigboard.WebCalendar.as_view()),
|
path('rigboard/calendar/', login_required()(rigboard.WebCalendar.as_view()),
|
||||||
name='web_calendar'),
|
name='web_calendar'),
|
||||||
url(r'^rigboard/calendar/(?P<view>(month|week|day))/$',
|
re_path(r'^rigboard/calendar/(?P<view>(month|week|day))/$',
|
||||||
login_required()(rigboard.WebCalendar.as_view()), name='web_calendar'),
|
login_required()(rigboard.WebCalendar.as_view()), name='web_calendar'),
|
||||||
url(r'^rigboard/calendar/(?P<view>(month|week|day))/(?P<date>(\d{4}-\d{2}-\d{2}))/$',
|
re_path(r'^rigboard/calendar/(?P<view>(month|week|day))/(?P<date>(\d{4}-\d{2}-\d{2}))/$',
|
||||||
login_required()(rigboard.WebCalendar.as_view()), name='web_calendar'),
|
login_required()(rigboard.WebCalendar.as_view()), name='web_calendar'),
|
||||||
path('rigboard/archive/', RedirectView.as_view(permanent=True, pattern_name='event_archive')),
|
path('rigboard/archive/', RedirectView.as_view(permanent=True, pattern_name='event_archive')),
|
||||||
|
|
||||||
@@ -130,11 +130,11 @@ urlpatterns = [
|
|||||||
path('event/<int:pk>/auth/preview/',
|
path('event/<int:pk>/auth/preview/',
|
||||||
permission_required_with_403('RIGS.change_event')(rigboard.EventAuthoriseRequestEmailPreview.as_view()),
|
permission_required_with_403('RIGS.change_event')(rigboard.EventAuthoriseRequestEmailPreview.as_view()),
|
||||||
name='event_authorise_preview'),
|
name='event_authorise_preview'),
|
||||||
url(r'^event/(?P<pk>\d+)/(?P<hmac>[-:\w]+)/$', rigboard.EventAuthorise.as_view(),
|
re_path(r'^event/(?P<pk>\d+)/(?P<hmac>[-:\w]+)/$', rigboard.EventAuthorise.as_view(),
|
||||||
name='event_authorise'),
|
name='event_authorise'),
|
||||||
|
|
||||||
# ICS Calendar - API key authentication
|
# ICS Calendar - API key authentication
|
||||||
url(r'^ical/(?P<api_pk>\d+)/(?P<api_key>\w+)/rigs.ics$', api_key_required(ical.CalendarICS()),
|
re_path(r'^ical/(?P<api_pk>\d+)/(?P<api_key>\w+)/rigs.ics$', api_key_required(ical.CalendarICS()),
|
||||||
name="ics_calendar"),
|
name="ics_calendar"),
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -338,293 +338,3 @@ class TestAssetAudit(AutoLoginTest):
|
|||||||
self.wait.until(animation_is_finished())
|
self.wait.until(animation_is_finished())
|
||||||
self.assertFalse(self.driver.find_element_by_id('modal').is_displayed())
|
self.assertFalse(self.driver.find_element_by_id('modal').is_displayed())
|
||||||
self.assertIn("Asset with that ID does not exist!", self.page.error.text)
|
self.assertIn("Asset with that ID does not exist!", self.page.error.text)
|
||||||
|
|
||||||
|
|
||||||
class TestSupplierValidation(TestCase):
|
|
||||||
@classmethod
|
|
||||||
def setUpTestData(cls):
|
|
||||||
cls.profile = rigsmodels.Profile.objects.create(username="SupplierValidationTest", email="SVT@test.com", is_superuser=True, is_active=True, is_staff=True)
|
|
||||||
cls.supplier = models.Supplier.objects.create(name="Gadgetron Corporation")
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.profile.set_password('testuser')
|
|
||||||
self.profile.save()
|
|
||||||
self.assertTrue(self.client.login(username=self.profile.username, password='testuser'))
|
|
||||||
|
|
||||||
def test_create(self):
|
|
||||||
url = reverse('supplier_create')
|
|
||||||
response = self.client.post(url)
|
|
||||||
self.assertFormError(response, 'form', 'name', 'This field is required.')
|
|
||||||
|
|
||||||
def test_edit(self):
|
|
||||||
url = reverse('supplier_update', kwargs={'pk': self.supplier.pk})
|
|
||||||
response = self.client.post(url, {'name': ""})
|
|
||||||
self.assertFormError(response, 'form', 'name', 'This field is required.')
|
|
||||||
|
|
||||||
|
|
||||||
class Test404(TestCase):
|
|
||||||
@classmethod
|
|
||||||
def setUpTestData(cls):
|
|
||||||
cls.profile = rigsmodels.Profile.objects.create(username="404Test", email="404@test.com", is_superuser=True, is_active=True, is_staff=True)
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.profile.set_password('testuser')
|
|
||||||
self.profile.save()
|
|
||||||
self.assertTrue(self.client.login(username=self.profile.username, password='testuser'))
|
|
||||||
|
|
||||||
def test(self):
|
|
||||||
urls = {'asset_detail', 'asset_update', 'asset_duplicate', 'supplier_detail', 'supplier_update'}
|
|
||||||
for url_name in urls:
|
|
||||||
request_url = reverse(url_name, kwargs={'pk': "0000"})
|
|
||||||
response = self.client.get(request_url, follow=True)
|
|
||||||
self.assertEqual(response.status_code, 404)
|
|
||||||
|
|
||||||
|
|
||||||
# TODO refactor this for all of RIGS
|
|
||||||
class TestAccessLevels(TestCase):
|
|
||||||
@override_settings(DEBUG=True)
|
|
||||||
def setUp(self):
|
|
||||||
super().setUp()
|
|
||||||
# Shortcut to create the levels - bonus side effect of testing the command (hopefully) matches production
|
|
||||||
call_command('generateSampleData')
|
|
||||||
# Create an asset with ID 1 to make things easier in loops (we can always use pk=1)
|
|
||||||
self.category = models.AssetCategory.objects.create(name="Number One")
|
|
||||||
self.status = models.AssetStatus.objects.create(name="Probably Fine", should_show=True)
|
|
||||||
models.Asset.objects.create(asset_id="1", description="Half Price Fish", status=self.status, category=self.category, date_acquired=datetime.date(2020, 2, 1))
|
|
||||||
|
|
||||||
# Nothing should be available to the unauthenticated
|
|
||||||
def test_unauthenticated(self):
|
|
||||||
self.client.logout()
|
|
||||||
for url in filter(lambda url: url.name is not None and "json" not in str(url), urls.urlpatterns):
|
|
||||||
pattern = str(url.pattern)
|
|
||||||
request_url = ""
|
|
||||||
if ":pk>" in pattern:
|
|
||||||
request_url = reverse(url.name, kwargs={'pk': 1})
|
|
||||||
else:
|
|
||||||
request_url = reverse(url.name)
|
|
||||||
if request_url:
|
|
||||||
response = self.client.get(request_url, follow=True, HTTP_HOST='example.com')
|
|
||||||
self.assertContains(response, 'Login')
|
|
||||||
|
|
||||||
def test_basic_access(self):
|
|
||||||
self.assertTrue(self.client.login(username="basic", password="basic"))
|
|
||||||
|
|
||||||
url = reverse('asset_list')
|
|
||||||
response = self.client.get(url)
|
|
||||||
# Check edit and duplicate buttons not shown in list
|
|
||||||
self.assertNotContains(response, 'Edit')
|
|
||||||
self.assertNotContains(response, 'Duplicate')
|
|
||||||
|
|
||||||
url = reverse('asset_detail', kwargs={'pk': "9000"})
|
|
||||||
response = self.client.get(url)
|
|
||||||
self.assertNotContains(response, 'Purchase Details')
|
|
||||||
self.assertNotContains(response, 'View Revision History')
|
|
||||||
|
|
||||||
urls = {'asset_history', 'asset_update', 'asset_duplicate'}
|
|
||||||
for url_name in urls:
|
|
||||||
request_url = reverse(url_name, kwargs={'pk': "9000"})
|
|
||||||
response = self.client.get(request_url, follow=True)
|
|
||||||
self.assertEqual(response.status_code, 403)
|
|
||||||
|
|
||||||
request_url = reverse('supplier_create')
|
|
||||||
response = self.client.get(request_url, follow=True)
|
|
||||||
self.assertEqual(response.status_code, 403)
|
|
||||||
|
|
||||||
request_url = reverse('supplier_update', kwargs={'pk': "1"})
|
|
||||||
response = self.client.get(request_url, follow=True)
|
|
||||||
self.assertEqual(response.status_code, 403)
|
|
||||||
|
|
||||||
def test_keyholder_access(self):
|
|
||||||
self.assertTrue(self.client.login(username="keyholder", password="keyholder"))
|
|
||||||
|
|
||||||
url = reverse('asset_list')
|
|
||||||
response = self.client.get(url)
|
|
||||||
# Check edit and duplicate buttons shown in list
|
|
||||||
self.assertContains(response, 'Edit')
|
|
||||||
self.assertContains(response, 'Duplicate')
|
|
||||||
|
|
||||||
url = reverse('asset_detail', kwargs={'pk': "9000"})
|
|
||||||
response = self.client.get(url)
|
|
||||||
self.assertContains(response, 'Purchase Details')
|
|
||||||
self.assertContains(response, 'View Revision History')
|
|
||||||
|
|
||||||
# def test_finance_access(self): Level not used in assets currently
|
|
||||||
|
|
||||||
def test_page_titles(self):
|
|
||||||
self.assertTrue(self.client.login(username="superuser", password="superuser"))
|
|
||||||
for url in filter(lambda url: url.name is not None and not any(s in url.name for s in ["json", "embed"]), urls.urlpatterns):
|
|
||||||
request_url = ""
|
|
||||||
if ":pk>" in str(url.pattern):
|
|
||||||
request_url = reverse(url.name, kwargs={'pk': "1"})
|
|
||||||
else:
|
|
||||||
request_url = reverse(url.name)
|
|
||||||
response = self.client.get(request_url)
|
|
||||||
if hasattr(response, "context_data") and "page_title" in response.context_data:
|
|
||||||
expected_title = response.context_data["page_title"]
|
|
||||||
self.assertContains(response, '<title>{} | Rig Information Gathering System</title>'.format(expected_title))
|
|
||||||
|
|
||||||
|
|
||||||
class TestFormValidation(TestCase):
|
|
||||||
@classmethod
|
|
||||||
def setUpTestData(cls):
|
|
||||||
cls.profile = rigsmodels.Profile.objects.create(username="AssetCreateValidationTest", email="acvt@test.com", is_superuser=True, is_active=True, is_staff=True)
|
|
||||||
cls.category = models.AssetCategory.objects.create(name="Sound")
|
|
||||||
cls.status = models.AssetStatus.objects.create(name="Broken", should_show=True)
|
|
||||||
cls.asset = models.Asset.objects.create(asset_id="9999", description="The Office", status=cls.status, category=cls.category, date_acquired=datetime.date(2018, 6, 15))
|
|
||||||
cls.connector = models.Connector.objects.create(description="16A IEC", current_rating=16, voltage_rating=240, num_pins=3)
|
|
||||||
cls.cable_type = models.CableType.objects.create(circuits=11, cores=3, plug=cls.connector, socket=cls.connector)
|
|
||||||
cls.cable_asset = models.Asset.objects.create(asset_id="666", description="125A -> Jack", comments="The cable from Hell...", status=cls.status, category=cls.category, date_acquired=datetime.date(2006, 6, 6), is_cable=True, cable_type=cls.cable_type, length=10, csa="1.5")
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.profile.set_password('testuser')
|
|
||||||
self.profile.save()
|
|
||||||
self.assertTrue(self.client.login(username=self.profile.username, password='testuser'))
|
|
||||||
|
|
||||||
def test_asset_create(self):
|
|
||||||
url = reverse('asset_create')
|
|
||||||
response = self.client.post(url, {'date_sold': '2000-01-01', 'date_acquired': '2020-01-01', 'purchase_price': '-30', 'salvage_value': '-30'})
|
|
||||||
self.assertFormError(response, 'form', 'asset_id', 'This field is required.')
|
|
||||||
self.assertFormError(response, 'form', 'description', 'This field is required.')
|
|
||||||
self.assertFormError(response, 'form', 'status', 'This field is required.')
|
|
||||||
self.assertFormError(response, 'form', 'category', 'This field is required.')
|
|
||||||
|
|
||||||
self.assertFormError(response, 'form', 'date_sold', 'Cannot sell an item before it is acquired')
|
|
||||||
self.assertFormError(response, 'form', 'purchase_price', 'A price cannot be negative')
|
|
||||||
self.assertFormError(response, 'form', 'salvage_value', 'A price cannot be negative')
|
|
||||||
|
|
||||||
def test_cable_create(self):
|
|
||||||
url = reverse('asset_create')
|
|
||||||
response = self.client.post(url, {'asset_id': 'X$%A', 'is_cable': True})
|
|
||||||
self.assertFormError(response, 'form', 'asset_id', 'An Asset ID can only consist of letters and numbers, with a final number')
|
|
||||||
|
|
||||||
self.assertFormError(response, 'form', 'cable_type', 'A cable must have a type')
|
|
||||||
self.assertFormError(response, 'form', 'length', 'The length of a cable must be more than 0')
|
|
||||||
self.assertFormError(response, 'form', 'csa', 'The CSA of a cable must be more than 0')
|
|
||||||
|
|
||||||
# Given that validation is done at model level it *shouldn't* need retesting...gonna do it anyway!
|
|
||||||
def test_asset_edit(self):
|
|
||||||
url = reverse('asset_update', kwargs={'pk': self.asset.asset_id})
|
|
||||||
response = self.client.post(url, {'date_sold': '2000-12-01', 'date_acquired': '2020-12-01', 'purchase_price': '-50', 'salvage_value': '-50', 'description': "", 'status': "", 'category': ""})
|
|
||||||
# self.assertFormError(response, 'form', 'asset_id', 'This field is required.')
|
|
||||||
self.assertFormError(response, 'form', 'description', 'This field is required.')
|
|
||||||
self.assertFormError(response, 'form', 'status', 'This field is required.')
|
|
||||||
self.assertFormError(response, 'form', 'category', 'This field is required.')
|
|
||||||
|
|
||||||
self.assertFormError(response, 'form', 'date_sold', 'Cannot sell an item before it is acquired')
|
|
||||||
self.assertFormError(response, 'form', 'purchase_price', 'A price cannot be negative')
|
|
||||||
self.assertFormError(response, 'form', 'salvage_value', 'A price cannot be negative')
|
|
||||||
|
|
||||||
def test_cable_edit(self):
|
|
||||||
url = reverse('asset_update', kwargs={'pk': self.cable_asset.asset_id})
|
|
||||||
# TODO Why do I have to send is_cable=True here?
|
|
||||||
response = self.client.post(url, {'is_cable': True, 'length': -3, 'csa': -3})
|
|
||||||
|
|
||||||
# TODO Can't figure out how to select the 'none' option...
|
|
||||||
# self.assertFormError(response, 'form', 'cable_type', 'A cable must have a type')
|
|
||||||
self.assertFormError(response, 'form', 'length', 'The length of a cable must be more than 0')
|
|
||||||
self.assertFormError(response, 'form', 'csa', 'The CSA of a cable must be more than 0')
|
|
||||||
|
|
||||||
def test_asset_duplicate(self):
|
|
||||||
url = reverse('asset_duplicate', kwargs={'pk': self.cable_asset.asset_id})
|
|
||||||
response = self.client.post(url, {'is_cable': True, 'length': 0, 'csa': 0})
|
|
||||||
|
|
||||||
self.assertFormError(response, 'form', 'length', 'The length of a cable must be more than 0')
|
|
||||||
self.assertFormError(response, 'form', 'csa', 'The CSA of a cable must be more than 0')
|
|
||||||
|
|
||||||
|
|
||||||
class TestSampleDataGenerator(TestCase):
|
|
||||||
@override_settings(DEBUG=True)
|
|
||||||
def test_generate_sample_data(self):
|
|
||||||
# Run the management command and check there are no exceptions
|
|
||||||
call_command('generateSampleAssetsData')
|
|
||||||
|
|
||||||
# Check there are lots
|
|
||||||
self.assertTrue(models.Asset.objects.all().count() > 50)
|
|
||||||
self.assertTrue(models.Supplier.objects.all().count() > 50)
|
|
||||||
|
|
||||||
@override_settings(DEBUG=True)
|
|
||||||
def test_delete_sample_data(self):
|
|
||||||
call_command('deleteSampleData')
|
|
||||||
|
|
||||||
self.assertTrue(models.Asset.objects.all().count() == 0)
|
|
||||||
self.assertTrue(models.Supplier.objects.all().count() == 0)
|
|
||||||
|
|
||||||
def test_production_exception(self):
|
|
||||||
from django.core.management.base import CommandError
|
|
||||||
|
|
||||||
self.assertRaisesRegex(CommandError, ".*production", call_command, 'generateSampleAssetsData')
|
|
||||||
self.assertRaisesRegex(CommandError, ".*production", call_command, 'deleteSampleData')
|
|
||||||
|
|
||||||
|
|
||||||
class TestEmbeddedViews(TestCase):
|
|
||||||
@classmethod
|
|
||||||
def setUpTestData(cls):
|
|
||||||
cls.profile = rigsmodels.Profile.objects.create(username="EmbeddedViewsTest", email="embedded@test.com", is_superuser=True, is_active=True, is_staff=True)
|
|
||||||
|
|
||||||
working = models.AssetStatus.objects.create(name="Working", should_show=True)
|
|
||||||
lighting = models.AssetCategory.objects.create(name="Lighting")
|
|
||||||
|
|
||||||
cls.assets = {
|
|
||||||
1: models.Asset.objects.create(asset_id="1991", description="Spaceflower", status=working, category=lighting, date_acquired=datetime.date(1991, 12, 26))
|
|
||||||
}
|
|
||||||
|
|
||||||
def setUp(self):
|
|
||||||
self.profile.set_password('testuser')
|
|
||||||
self.profile.save()
|
|
||||||
|
|
||||||
def testLoginRedirect(self):
|
|
||||||
request_url = reverse('asset_embed', kwargs={'pk': self.assets[1].asset_id})
|
|
||||||
expected_url = "{0}?next={1}".format(reverse('login_embed'), request_url)
|
|
||||||
|
|
||||||
# Request the page and check it redirects
|
|
||||||
response = self.client.get(request_url, follow=True)
|
|
||||||
self.assertRedirects(response, expected_url, status_code=302, target_status_code=200)
|
|
||||||
|
|
||||||
# Now login
|
|
||||||
self.assertTrue(self.client.login(username=self.profile.username, password='testuser'))
|
|
||||||
|
|
||||||
# And check that it no longer redirects
|
|
||||||
response = self.client.get(request_url, follow=True)
|
|
||||||
self.assertEqual(len(response.redirect_chain), 0)
|
|
||||||
|
|
||||||
def testLoginCookieWarning(self):
|
|
||||||
login_url = reverse('login_embed')
|
|
||||||
response = self.client.post(login_url, follow=True)
|
|
||||||
self.assertContains(response, "Cookies do not seem to be enabled")
|
|
||||||
|
|
||||||
def testXFrameHeaders(self):
|
|
||||||
asset_url = reverse('asset_embed', kwargs={'pk': self.assets[1].asset_id})
|
|
||||||
login_url = reverse('login_embed')
|
|
||||||
|
|
||||||
self.assertTrue(self.client.login(username=self.profile.username, password='testuser'))
|
|
||||||
|
|
||||||
response = self.client.get(asset_url, follow=True)
|
|
||||||
with self.assertRaises(KeyError):
|
|
||||||
response._headers["X-Frame-Options"]
|
|
||||||
|
|
||||||
response = self.client.get(login_url, follow=True)
|
|
||||||
with self.assertRaises(KeyError):
|
|
||||||
response._headers["X-Frame-Options"]
|
|
||||||
|
|
||||||
def testOEmbed(self):
|
|
||||||
asset_url = reverse('asset_detail', kwargs={'pk': self.assets[1].asset_id})
|
|
||||||
asset_embed_url = reverse('asset_embed', kwargs={'pk': self.assets[1].asset_id})
|
|
||||||
oembed_url = reverse('asset_oembed', kwargs={'pk': self.assets[1].asset_id})
|
|
||||||
|
|
||||||
alt_oembed_url = reverse('asset_oembed', kwargs={'pk': 999})
|
|
||||||
alt_asset_embed_url = reverse('asset_embed', kwargs={'pk': 999})
|
|
||||||
|
|
||||||
# Test the meta tag is in place
|
|
||||||
response = self.client.get(asset_url, follow=True, HTTP_HOST='example.com')
|
|
||||||
self.assertContains(response, '<link rel="alternate" type="application/json+oembed"')
|
|
||||||
self.assertContains(response, oembed_url)
|
|
||||||
|
|
||||||
# Test that the JSON exists
|
|
||||||
response = self.client.get(oembed_url, follow=True, HTTP_HOST='example.com')
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
self.assertContains(response, asset_embed_url)
|
|
||||||
|
|
||||||
# Should also work for non-existant
|
|
||||||
response = self.client.get(alt_oembed_url, follow=True, HTTP_HOST='example.com')
|
|
||||||
self.assertEqual(response.status_code, 200)
|
|
||||||
self.assertContains(response, alt_asset_embed_url)
|
|
||||||
296
assets/tests/test_unit.py
Normal file
296
assets/tests/test_unit.py
Normal file
@@ -0,0 +1,296 @@
|
|||||||
|
from django.core.management import call_command
|
||||||
|
from assets import models
|
||||||
|
from django.test.utils import override_settings
|
||||||
|
from django.urls import reverse
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
from assets import models, urls
|
||||||
|
from reversion import revisions as reversion
|
||||||
|
import datetime
|
||||||
|
from django.utils import timezone
|
||||||
|
from django.test import tag
|
||||||
|
import pytest
|
||||||
|
from pytest_django.asserts import assertFormError, assertRedirects
|
||||||
|
|
||||||
|
pytestmark = pytest.mark.django_db # TODO
|
||||||
|
|
||||||
|
|
||||||
|
def response_contains(response, needle):
|
||||||
|
return needle in str(response.content)
|
||||||
|
|
||||||
|
|
||||||
|
def login(client, django_user_model):
|
||||||
|
pwd = 'testuser'
|
||||||
|
usr = "TestUser"
|
||||||
|
profile = django_user_model.objects.create_user(username=usr, email="TestUser@test.com", password=pwd, is_superuser=True, is_active=True, is_staff=True)
|
||||||
|
assert client.login(username=usr, password=pwd)
|
||||||
|
|
||||||
|
|
||||||
|
def create_test_asset():
|
||||||
|
working = models.AssetStatus.objects.create(name="Working", should_show=True)
|
||||||
|
lighting = models.AssetCategory.objects.create(name="Lighting")
|
||||||
|
asset = models.Asset.objects.create(asset_id="1991", description="Spaceflower", status=working, category=lighting, date_acquired=datetime.date(1991, 12, 26))
|
||||||
|
return asset
|
||||||
|
|
||||||
|
|
||||||
|
def create_test_cable():
|
||||||
|
category = models.AssetCategory.objects.create(name="Sound")
|
||||||
|
status = models.AssetStatus.objects.create(name="Broken", should_show=True)
|
||||||
|
connector = models.Connector.objects.create(description="16A IEC", current_rating=16, voltage_rating=240, num_pins=3)
|
||||||
|
cable_type = models.CableType.objects.create(circuits=11, cores=3, plug=connector, socket=connector)
|
||||||
|
return models.Asset.objects.create(asset_id="666", description="125A -> Jack", comments="The cable from Hell...", status=status, category=category, date_acquired=datetime.date(2006, 6, 6), is_cable=True, cable_type=cable_type, length=10, csa="1.5")
|
||||||
|
|
||||||
|
|
||||||
|
def test_supplier_create(client, django_user_model):
|
||||||
|
login(client, django_user_model)
|
||||||
|
url = reverse('supplier_create')
|
||||||
|
response = client.post(url)
|
||||||
|
assertFormError(response, 'form', 'name', 'This field is required.')
|
||||||
|
|
||||||
|
|
||||||
|
def test_supplier_edit(client, django_user_model):
|
||||||
|
login(client, django_user_model)
|
||||||
|
supplier = models.Supplier.objects.create(name="Gadgetron Corporation")
|
||||||
|
url = reverse('supplier_update', kwargs={'pk': supplier.pk})
|
||||||
|
response = client.post(url, {'name': ""})
|
||||||
|
assertFormError(response, 'form', 'name', 'This field is required.')
|
||||||
|
|
||||||
|
|
||||||
|
def test_404(client, django_user_model):
|
||||||
|
login(client, django_user_model)
|
||||||
|
urls = {'asset_detail', 'asset_update', 'asset_duplicate', 'supplier_detail', 'supplier_update'}
|
||||||
|
for url_name in urls:
|
||||||
|
request_url = reverse(url_name, kwargs={'pk': "0000"})
|
||||||
|
response = client.get(request_url, follow=True)
|
||||||
|
assert response.status_code == 404
|
||||||
|
|
||||||
|
|
||||||
|
def test_embed_login_redirect(client, django_user_model):
|
||||||
|
request_url = reverse('asset_embed', kwargs={'pk': create_test_asset().asset_id})
|
||||||
|
expected_url = "{0}?next={1}".format(reverse('login_embed'), request_url)
|
||||||
|
|
||||||
|
# Request the page and check it redirects
|
||||||
|
response = client.get(request_url, follow=True)
|
||||||
|
assertRedirects(response, expected_url, status_code=302, target_status_code=200)
|
||||||
|
|
||||||
|
# Now login
|
||||||
|
login(client, django_user_model)
|
||||||
|
|
||||||
|
# And check that it no longer redirects
|
||||||
|
response = client.get(request_url, follow=True)
|
||||||
|
assert len(response.redirect_chain) == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_login_cookie_warning(client, django_user_model):
|
||||||
|
login_url = reverse('login_embed')
|
||||||
|
response = client.post(login_url, follow=True)
|
||||||
|
assert "Cookies do not seem to be enabled" in str(response.content)
|
||||||
|
|
||||||
|
|
||||||
|
def test_x_frame_headers(client, django_user_model):
|
||||||
|
asset_url = reverse('asset_embed', kwargs={'pk': create_test_asset().asset_id})
|
||||||
|
login_url = reverse('login_embed')
|
||||||
|
|
||||||
|
login(client, django_user_model)
|
||||||
|
|
||||||
|
response = client.get(asset_url, follow=True)
|
||||||
|
with pytest.raises(KeyError):
|
||||||
|
response._headers["X-Frame-Options"]
|
||||||
|
|
||||||
|
response = client.get(login_url, follow=True)
|
||||||
|
with pytest.raises(KeyError):
|
||||||
|
response._headers["X-Frame-Options"]
|
||||||
|
|
||||||
|
|
||||||
|
def test_oembed(client):
|
||||||
|
asset = create_test_asset()
|
||||||
|
asset_url = reverse('asset_detail', kwargs={'pk': asset.asset_id})
|
||||||
|
asset_embed_url = reverse('asset_embed', kwargs={'pk': asset.asset_id})
|
||||||
|
oembed_url = reverse('asset_oembed', kwargs={'pk': asset.asset_id})
|
||||||
|
|
||||||
|
alt_oembed_url = reverse('asset_oembed', kwargs={'pk': 999})
|
||||||
|
alt_asset_embed_url = reverse('asset_embed', kwargs={'pk': 999})
|
||||||
|
|
||||||
|
# Test the meta tag is in place
|
||||||
|
response = client.get(asset_url, follow=True, HTTP_HOST='example.com')
|
||||||
|
assert '<link rel="alternate" type="application/json+oembed"' in str(response.content)
|
||||||
|
assert oembed_url in str(response.content)
|
||||||
|
|
||||||
|
# Test that the JSON exists
|
||||||
|
response = client.get(oembed_url, follow=True, HTTP_HOST='example.com')
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert asset_embed_url in str(response.content)
|
||||||
|
|
||||||
|
# Should also work for non-existant
|
||||||
|
response = client.get(alt_oembed_url, follow=True, HTTP_HOST='example.com')
|
||||||
|
assert response.status_code == 200
|
||||||
|
assert alt_asset_embed_url in str(response.content)
|
||||||
|
|
||||||
|
|
||||||
|
@override_settings(DEBUG=True)
|
||||||
|
def test_generate_sample_data(client):
|
||||||
|
# Run the management command and check there are no exceptions
|
||||||
|
call_command('generateSampleAssetsData')
|
||||||
|
|
||||||
|
# Check there are lots
|
||||||
|
assert models.Asset.objects.all().count() > 50
|
||||||
|
assert models.Supplier.objects.all().count() > 50
|
||||||
|
|
||||||
|
|
||||||
|
@override_settings(DEBUG=True)
|
||||||
|
def test_delete_sample_data(client):
|
||||||
|
call_command('deleteSampleData')
|
||||||
|
|
||||||
|
assert models.Asset.objects.all().count() == 0
|
||||||
|
assert models.Supplier.objects.all().count() == 0
|
||||||
|
|
||||||
|
|
||||||
|
def test_production_exception(client):
|
||||||
|
from django.core.management.base import CommandError
|
||||||
|
|
||||||
|
with pytest.raises(CommandError, match=".*production"):
|
||||||
|
call_command('generateSampleAssetsData')
|
||||||
|
call_command('deleteSampleData')
|
||||||
|
|
||||||
|
|
||||||
|
def test_asset_create(client, django_user_model):
|
||||||
|
login(client, django_user_model)
|
||||||
|
response = client.post(reverse('asset_create'), {'date_sold': '2000-01-01', 'date_acquired': '2020-01-01', 'purchase_price': '-30', 'salvage_value': '-30'})
|
||||||
|
assertFormError(response, 'form', 'asset_id', 'This field is required.')
|
||||||
|
assertFormError(response, 'form', 'description', 'This field is required.')
|
||||||
|
assertFormError(response, 'form', 'status', 'This field is required.')
|
||||||
|
assertFormError(response, 'form', 'category', 'This field is required.')
|
||||||
|
|
||||||
|
assertFormError(response, 'form', 'date_sold', 'Cannot sell an item before it is acquired')
|
||||||
|
assertFormError(response, 'form', 'purchase_price', 'A price cannot be negative')
|
||||||
|
assertFormError(response, 'form', 'salvage_value', 'A price cannot be negative')
|
||||||
|
|
||||||
|
|
||||||
|
def test_cable_create(client, django_user_model):
|
||||||
|
login(client, django_user_model)
|
||||||
|
response = client.post(reverse('asset_create'), {'asset_id': 'X$%A', 'is_cable': True})
|
||||||
|
assertFormError(response, 'form', 'asset_id', 'An Asset ID can only consist of letters and numbers, with a final number')
|
||||||
|
|
||||||
|
assertFormError(response, 'form', 'cable_type', 'A cable must have a type')
|
||||||
|
assertFormError(response, 'form', 'length', 'The length of a cable must be more than 0')
|
||||||
|
assertFormError(response, 'form', 'csa', 'The CSA of a cable must be more than 0')
|
||||||
|
|
||||||
|
# Given that validation is done at model level it *shouldn't* need retesting...gonna do it anyway!
|
||||||
|
|
||||||
|
|
||||||
|
def test_asset_edit(client, django_user_model):
|
||||||
|
login(client, django_user_model)
|
||||||
|
url = reverse('asset_update', kwargs={'pk': create_test_asset().asset_id})
|
||||||
|
response = client.post(url, {'date_sold': '2000-12-01', 'date_acquired': '2020-12-01', 'purchase_price': '-50', 'salvage_value': '-50', 'description': "", 'status': "", 'category': ""})
|
||||||
|
# assertFormError(response, 'form', 'asset_id', 'This field is required.')
|
||||||
|
assertFormError(response, 'form', 'description', 'This field is required.')
|
||||||
|
assertFormError(response, 'form', 'status', 'This field is required.')
|
||||||
|
assertFormError(response, 'form', 'category', 'This field is required.')
|
||||||
|
assertFormError(response, 'form', 'date_sold', 'Cannot sell an item before it is acquired')
|
||||||
|
assertFormError(response, 'form', 'purchase_price', 'A price cannot be negative')
|
||||||
|
assertFormError(response, 'form', 'salvage_value', 'A price cannot be negative')
|
||||||
|
|
||||||
|
|
||||||
|
def test_cable_edit(client, django_user_model):
|
||||||
|
login(client, django_user_model)
|
||||||
|
url = reverse('asset_update', kwargs={'pk': create_test_cable().asset_id})
|
||||||
|
# TODO Why do I have to send is_cable=True here?
|
||||||
|
response = client.post(url, {'is_cable': True, 'length': -3, 'csa': -3})
|
||||||
|
|
||||||
|
# TODO Can't figure out how to select the 'none' option...
|
||||||
|
# assertFormError(response, 'form', 'cable_type', 'A cable must have a type')
|
||||||
|
assertFormError(response, 'form', 'length', 'The length of a cable must be more than 0')
|
||||||
|
assertFormError(response, 'form', 'csa', 'The CSA of a cable must be more than 0')
|
||||||
|
|
||||||
|
|
||||||
|
def test_asset_duplicate(client, django_user_model):
|
||||||
|
login(client, django_user_model)
|
||||||
|
url = reverse('asset_duplicate', kwargs={'pk': create_test_cable().asset_id})
|
||||||
|
response = client.post(url, {'is_cable': True, 'length': 0, 'csa': 0})
|
||||||
|
|
||||||
|
assertFormError(response, 'form', 'length', 'The length of a cable must be more than 0')
|
||||||
|
assertFormError(response, 'form', 'csa', 'The CSA of a cable must be more than 0')
|
||||||
|
|
||||||
|
|
||||||
|
@override_settings(DEBUG=True)
|
||||||
|
def create_asset_one():
|
||||||
|
# Shortcut to create the levels - bonus side effect of testing the command (hopefully) matches production
|
||||||
|
call_command('generateSampleData')
|
||||||
|
# Create an asset with ID 1 to make things easier in loops (we can always use pk=1)
|
||||||
|
category = models.AssetCategory.objects.create(name="Number One")
|
||||||
|
status = models.AssetStatus.objects.create(name="Probably Fine", should_show=True)
|
||||||
|
return models.Asset.objects.create(asset_id="1", description="Half Price Fish", status=status, category=category, date_acquired=datetime.date(2020, 2, 1))
|
||||||
|
|
||||||
|
# Nothing should be available to the unauthenticated
|
||||||
|
|
||||||
|
|
||||||
|
def test_unauthenticated(client):
|
||||||
|
for url in filter(lambda url: url.name is not None and "json" not in str(url), urls.urlpatterns):
|
||||||
|
pattern = str(url.pattern)
|
||||||
|
request_url = ""
|
||||||
|
if ":pk>" in pattern:
|
||||||
|
request_url = reverse(url.name, kwargs={'pk': 1})
|
||||||
|
else:
|
||||||
|
request_url = reverse(url.name)
|
||||||
|
if request_url:
|
||||||
|
response = client.get(request_url, follow=True, HTTP_HOST='example.com')
|
||||||
|
# TODO Check the URL here
|
||||||
|
assert response_contains(response, 'Login')
|
||||||
|
|
||||||
|
|
||||||
|
def test_basic_access(client):
|
||||||
|
create_asset_one()
|
||||||
|
client.login(username="basic", password="basic")
|
||||||
|
|
||||||
|
url = reverse('asset_list')
|
||||||
|
response = client.get(url)
|
||||||
|
# Check edit and duplicate buttons NOT shown in list
|
||||||
|
assert not response_contains(response, 'Edit')
|
||||||
|
assert not response_contains(response, 'Duplicate')
|
||||||
|
|
||||||
|
url = reverse('asset_detail', kwargs={'pk': "9000"})
|
||||||
|
response = client.get(url)
|
||||||
|
assert not response_contains(response, 'Purchase Details')
|
||||||
|
assert not response_contains(response, 'View Revision History')
|
||||||
|
|
||||||
|
urls = {'asset_history', 'asset_update', 'asset_duplicate'}
|
||||||
|
for url_name in urls:
|
||||||
|
request_url = reverse(url_name, kwargs={'pk': "9000"})
|
||||||
|
response = client.get(request_url, follow=True)
|
||||||
|
assert response.status_code == 403
|
||||||
|
|
||||||
|
request_url = reverse('supplier_create')
|
||||||
|
response = client.get(request_url, follow=True)
|
||||||
|
assert response.status_code == 403
|
||||||
|
|
||||||
|
request_url = reverse('supplier_update', kwargs={'pk': "1"})
|
||||||
|
response = client.get(request_url, follow=True)
|
||||||
|
assert response.status_code == 403
|
||||||
|
|
||||||
|
|
||||||
|
def test_keyholder_access(client):
|
||||||
|
create_asset_one()
|
||||||
|
client.login(username="keyholder", password="keyholder")
|
||||||
|
|
||||||
|
url = reverse('asset_list')
|
||||||
|
response = client.get(url)
|
||||||
|
# Check edit and duplicate buttons shown in list
|
||||||
|
assert response_contains(response, 'Edit')
|
||||||
|
assert response_contains(response, 'Duplicate')
|
||||||
|
|
||||||
|
url = reverse('asset_detail', kwargs={'pk': "9000"})
|
||||||
|
response = client.get(url)
|
||||||
|
assert response_contains(response, 'Purchase Details')
|
||||||
|
assert response_contains(response, 'View Revision History')
|
||||||
|
|
||||||
|
|
||||||
|
def test_page_titles(admin_client):
|
||||||
|
for url in filter(lambda url: url.name is not None and not any(s in url.name for s in ["json", "embed"]), urls.urlpatterns):
|
||||||
|
request_url = ""
|
||||||
|
if ":pk>" in str(url.pattern):
|
||||||
|
request_url = reverse(url.name, kwargs={'pk': "1"})
|
||||||
|
else:
|
||||||
|
request_url = reverse(url.name)
|
||||||
|
response = admin_client.get(request_url)
|
||||||
|
if hasattr(response, "context_data") and "page_title" in response.context_data:
|
||||||
|
expected_title = response.context_data["page_title"]
|
||||||
|
assert response_contains(response, '<title>{} | Rig Information Gathering System</title>'.format(expected_title))
|
||||||
@@ -14,7 +14,7 @@ from django.utils.decorators import method_decorator
|
|||||||
from django.views import generic
|
from django.views import generic
|
||||||
from django.views.decorators.csrf import csrf_exempt
|
from django.views.decorators.csrf import csrf_exempt
|
||||||
from versioning import versioning
|
from versioning import versioning
|
||||||
from PyRIGS.views import GenericListView, GenericDetailView, GenericUpdateView, GenericCreateView, ModalURLMixin
|
from PyRIGS.views import GenericListView, GenericDetailView, GenericUpdateView, GenericCreateView, ModalURLMixin, is_ajax
|
||||||
from itertools import chain
|
from itertools import chain
|
||||||
|
|
||||||
|
|
||||||
@@ -121,7 +121,7 @@ class AssetEdit(LoginRequiredMixin, AssetIDUrlMixin, generic.UpdateView):
|
|||||||
return context
|
return context
|
||||||
|
|
||||||
def get_success_url(self):
|
def get_success_url(self):
|
||||||
if self.request.is_ajax():
|
if is_ajax(self.request):
|
||||||
url = reverse_lazy('closemodal')
|
url = reverse_lazy('closemodal')
|
||||||
update_url = str(reverse_lazy('asset_update', kwargs={'pk': self.object.pk}))
|
update_url = str(reverse_lazy('asset_update', kwargs={'pk': self.object.pk}))
|
||||||
messages.info(self.request, "modalobject=" + serializers.serialize("json", [self.object]))
|
messages.info(self.request, "modalobject=" + serializers.serialize("json", [self.object]))
|
||||||
@@ -235,7 +235,7 @@ class SupplierList(GenericListView):
|
|||||||
context['edit'] = 'supplier_update'
|
context['edit'] = 'supplier_update'
|
||||||
context['can_edit'] = self.request.user.has_perm('assets.change_supplier')
|
context['can_edit'] = self.request.user.has_perm('assets.change_supplier')
|
||||||
context['detail'] = 'supplier_detail'
|
context['detail'] = 'supplier_detail'
|
||||||
if self.request.is_ajax():
|
if is_ajax(self.request):
|
||||||
context['override'] = "base_ajax.html"
|
context['override'] = "base_ajax.html"
|
||||||
else:
|
else:
|
||||||
context['override'] = 'base_assets.html'
|
context['override'] = 'base_assets.html'
|
||||||
@@ -263,7 +263,7 @@ class SupplierDetail(GenericDetailView):
|
|||||||
context['detail_link'] = 'supplier_detail'
|
context['detail_link'] = 'supplier_detail'
|
||||||
context['associated'] = 'partials/associated_assets.html'
|
context['associated'] = 'partials/associated_assets.html'
|
||||||
context['associated2'] = ''
|
context['associated2'] = ''
|
||||||
if self.request.is_ajax():
|
if is_ajax(self.request):
|
||||||
context['override'] = "base_ajax.html"
|
context['override'] = "base_ajax.html"
|
||||||
else:
|
else:
|
||||||
context['override'] = 'base_assets.html'
|
context['override'] = 'base_assets.html'
|
||||||
@@ -277,7 +277,7 @@ class SupplierCreate(GenericCreateView, ModalURLMixin):
|
|||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(SupplierCreate, self).get_context_data(**kwargs)
|
context = super(SupplierCreate, self).get_context_data(**kwargs)
|
||||||
if self.request.is_ajax():
|
if is_ajax(self.request):
|
||||||
context['override'] = "base_ajax.html"
|
context['override'] = "base_ajax.html"
|
||||||
else:
|
else:
|
||||||
context['override'] = 'base_assets.html'
|
context['override'] = 'base_assets.html'
|
||||||
@@ -293,7 +293,7 @@ class SupplierUpdate(GenericUpdateView, ModalURLMixin):
|
|||||||
|
|
||||||
def get_context_data(self, **kwargs):
|
def get_context_data(self, **kwargs):
|
||||||
context = super(SupplierUpdate, self).get_context_data(**kwargs)
|
context = super(SupplierUpdate, self).get_context_data(**kwargs)
|
||||||
if self.request.is_ajax():
|
if is_ajax(self.request):
|
||||||
context['override'] = "base_ajax.html"
|
context['override'] = "base_ajax.html"
|
||||||
else:
|
else:
|
||||||
context['override'] = 'base_assets.html'
|
context['override'] = 'base_assets.html'
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
[pytest]
|
[pytest]
|
||||||
DJANGO_SETTINGS_MODULE = myproject.settings
|
DJANGO_SETTINGS_MODULE = PyRIGS.settings
|
||||||
|
# FAIL_INVALID_TEMPLATE_VARS = True
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ premailer==3.7.0
|
|||||||
progress==1.5
|
progress==1.5
|
||||||
psutil==5.8.0
|
psutil==5.8.0
|
||||||
psycopg2==2.8.6
|
psycopg2==2.8.6
|
||||||
psycopg2-binary==2.8.6
|
|
||||||
Pygments==2.7.4
|
Pygments==2.7.4
|
||||||
pyparsing==2.4.7
|
pyparsing==2.4.7
|
||||||
PyPDF2==1.26.0
|
PyPDF2==1.26.0
|
||||||
@@ -50,6 +49,9 @@ PyPOM==2.2.0
|
|||||||
python-dateutil==2.8.1
|
python-dateutil==2.8.1
|
||||||
pytoml==0.1.21
|
pytoml==0.1.21
|
||||||
pytz==2020.5
|
pytz==2020.5
|
||||||
|
pytest-django==4.1.0
|
||||||
|
pytest-xdist==2.2.0
|
||||||
|
pytest-cov==2.11.1
|
||||||
raven==6.10.0
|
raven==6.10.0
|
||||||
reportlab==3.5.60
|
reportlab==3.5.60
|
||||||
requests==2.25.1
|
requests==2.25.1
|
||||||
|
|||||||
@@ -305,6 +305,3 @@ class TestVersioningViews(TestCase):
|
|||||||
response = self.client.get(request_url, follow=True)
|
response = self.client.get(request_url, follow=True)
|
||||||
self.assertContains(response, "Test Person")
|
self.assertContains(response, "Test Person")
|
||||||
self.assertEqual(response.status_code, 200)
|
self.assertEqual(response.status_code, 200)
|
||||||
|
|
||||||
|
|
||||||
# Functional Tests
|
|
||||||
|
|||||||
Reference in New Issue
Block a user