mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-02-11 17:19:42 +00:00
Fix various minor issues (#545)
* Add absolute URL to power tests * Update to target Python 3.10 * Return user to current page when clicking 'mark reviewed' * Add units to power test record detail and form I'm a bad scientist (coz I'm an engineer) * Allow a higher value in PSSC fields * Default venue to event venue in EC/PT * Fix population of initial venue values for EC/PT * Add link to create power test from EC detail * Do not set power plan field to required on RA "This might be a problem if the risk assessment is being done by one person and the power plan by another." * Default power MIC to MIC * Implement some suggestions from the Doctor * Prevent checking in to cancelled events and dry hires Will close #539 * Exclude dry hires from H&S overview list * Add "ex VAT" tooltips to asset purchase price and replacement cost * Automagically clear and focus ID field when audit modal closes Closes #533 * Delete unused things * Allow two decimal places in cable length, show training item IDs in selectpicker Will close #540 * Fix #524 500 Error when viewing qualification list for items nobody is qualified in * Update README.md * Add a guard against nulls in recent changes Maybe fixes #537 I'm unable to replicate locally * Turn down verbosity of CI tests, fix tests, potential speedup * Squash migration * Add encoding to open * Update to v3 upload-artifact Resolves a deprecation warning
This commit is contained in:
5
.github/workflows/django.yml
vendored
5
.github/workflows/django.yml
vendored
@@ -12,6 +12,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PYTHONDONTWRITEBYTECODE: 1
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up Python
|
||||
@@ -41,8 +42,8 @@ jobs:
|
||||
pipenv run python3 manage.py makemigrations --check --dry-run
|
||||
pipenv run python3 manage.py collectstatic --noinput
|
||||
- name: Run Tests
|
||||
run: pipenv run pytest -n auto -vv --cov
|
||||
- uses: actions/upload-artifact@v2
|
||||
run: pipenv run pytest -n auto --cov
|
||||
- uses: actions/upload-artifact@v3
|
||||
if: failure()
|
||||
with:
|
||||
name: failure-screenshots ${{ matrix.test-group }}
|
||||
|
||||
2
Pipfile
2
Pipfile
@@ -93,7 +93,7 @@ pytest = "*"
|
||||
pytest-reverse = "*"
|
||||
|
||||
[requires]
|
||||
python_version = "3.9"
|
||||
python_version = "3.10"
|
||||
|
||||
[dev-packages.pytest-xdist]
|
||||
extras = [ "psutil",]
|
||||
|
||||
104
Pipfile.lock
generated
104
Pipfile.lock
generated
@@ -1,11 +1,11 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "9865ac4d5b85c2b9461dcfe9391f319bce4416b009ced82b8f8fe2ea5b7d9d7a"
|
||||
"sha256": "71377846d2282aa2f5352819eb31260cbbb04f41c2c3462b5c3ca2c8bc602b34"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.9"
|
||||
"python_version": "3.10"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
@@ -263,7 +263,7 @@
|
||||
"sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df",
|
||||
"sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"markers": "python_full_version >= '3.7.0'",
|
||||
"version": "==3.1.0"
|
||||
},
|
||||
"configparser": {
|
||||
@@ -1006,11 +1006,11 @@
|
||||
},
|
||||
"sentry-sdk": {
|
||||
"hashes": [
|
||||
"sha256:5932c092c6e6035584eb74d77064e4bce3b7935dfc4a331349719a40db265840",
|
||||
"sha256:cf89a5063ef84278d186aceaed6fb595bfe67d099298e537634a323664265669"
|
||||
"sha256:0bbcecda9f51936904c1030e7fef0fe693e633888f02a14d1cb68646a50e83b3",
|
||||
"sha256:56d6d9d194c898d853a7c1dd99bed92ce82334ee1282292c15bcc967ff1a49b5"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.22.2"
|
||||
"version": "==1.24.0"
|
||||
},
|
||||
"setuptools": {
|
||||
"hashes": [
|
||||
@@ -1206,11 +1206,11 @@
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305",
|
||||
"sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42"
|
||||
"sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f",
|
||||
"sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.26.15"
|
||||
"version": "==1.26.16"
|
||||
},
|
||||
"webencodings": {
|
||||
"hashes": [
|
||||
@@ -1232,7 +1232,7 @@
|
||||
"sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065",
|
||||
"sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"markers": "python_full_version >= '3.7.0'",
|
||||
"version": "==1.2.0"
|
||||
},
|
||||
"yolk": {
|
||||
@@ -1552,7 +1552,7 @@
|
||||
"sha256:f8303414c7b03f794347ad062c0516cee0e15f7a612abd0ce1e25caf6ceb47df",
|
||||
"sha256:fca62a8301b605b954ad2e9c3666f9d97f63872aa4efcae5492baca2056b74ab"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"markers": "python_full_version >= '3.7.0'",
|
||||
"version": "==3.1.0"
|
||||
},
|
||||
"coverage": {
|
||||
@@ -1765,11 +1765,11 @@
|
||||
},
|
||||
"pytest-cov": {
|
||||
"hashes": [
|
||||
"sha256:2feb1b751d66a8bd934e5edfa2e961d11309dc37b73b0eabe73b5945fee20f6b",
|
||||
"sha256:996b79efde6433cdbd0088872dbc5fb3ed7fe1578b68cdbba634f14bb8dd0470"
|
||||
"sha256:3904b13dfbfec47f003b8e77fd5b589cd11904a21ddf1ab38a64f204d6a10ef6",
|
||||
"sha256:6ba70b9e97e69fcc3fb45bfeab2d0a138fb65c4d0d6a41ef33983ad114be8c3a"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.0.0"
|
||||
"version": "==4.1.0"
|
||||
},
|
||||
"pytest-django": {
|
||||
"hashes": [
|
||||
@@ -1800,11 +1800,11 @@
|
||||
"psutil"
|
||||
],
|
||||
"hashes": [
|
||||
"sha256:1849bd98d8b242b948e472db7478e090bf3361912a8fed87992ed94085f54727",
|
||||
"sha256:37290d161638a20b672401deef1cba812d110ac27e35d213f091d15b8beb40c9"
|
||||
"sha256:d5ee0520eb1b7bcca50a60a518ab7a7707992812c578198f8b44fdfac78e8c93",
|
||||
"sha256:ff9daa7793569e6a68544850fd3927cd257cc03a7ef76c95e86915355e82b5f2"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.2.1"
|
||||
"version": "==3.3.1"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
@@ -1878,18 +1878,18 @@
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:8a388717b9476f934a21484e8c8e61875ab60644d29b9b39e11e4b9dc1c6b305",
|
||||
"sha256:aa751d169e23c7479ce47a0cb0da579e3ede798f994f5816a74e4f4500dcea42"
|
||||
"sha256:8d36afa7616d8ab714608411b4a3b13e58f463aee519024578e062e141dce20f",
|
||||
"sha256:8f135f6502756bde6b2a9b28989df5fbe87c9970cecaa69041edcce7f0589b14"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.26.15"
|
||||
"version": "==1.26.16"
|
||||
},
|
||||
"wsproto": {
|
||||
"hashes": [
|
||||
"sha256:ad565f26ecb92588a3e43bc3d96164de84cd9902482b130d0ddbaa9664a85065",
|
||||
"sha256:b9acddd652b585d75b20477888c56642fdade28bdfd3579aa24a4d2c037dd736"
|
||||
],
|
||||
"markers": "python_version >= '3.7'",
|
||||
"markers": "python_full_version >= '3.7.0'",
|
||||
"version": "==1.2.0"
|
||||
},
|
||||
"zope.component": {
|
||||
@@ -1900,6 +1900,22 @@
|
||||
"index": "pypi",
|
||||
"version": "==4.6.2"
|
||||
},
|
||||
"zope.deferredimport": {
|
||||
"hashes": [
|
||||
"sha256:57b2345e7b5eef47efcd4f634ff16c93e4265de3dcf325afc7315ade48d909e1",
|
||||
"sha256:9a0c211df44aa95f1c4e6d2626f90b400f56989180d3ef96032d708da3d23e0a"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.3.1"
|
||||
},
|
||||
"zope.deprecation": {
|
||||
"hashes": [
|
||||
"sha256:0d453338f04bacf91bbfba545d8bcdf529aa829e67b705eac8c1a7fdce66e2df",
|
||||
"sha256:f1480b74995958b24ce37b0ef04d3663d2683e5d6debc96726eff18acf4ea113"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.4.0"
|
||||
},
|
||||
"zope.event": {
|
||||
"hashes": [
|
||||
"sha256:2666401939cdaa5f4e0c08cf7f20c9b21423b95e88f4675b1443973bdb080c42",
|
||||
@@ -2011,6 +2027,52 @@
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==5.2.0"
|
||||
},
|
||||
"zope.proxy": {
|
||||
"hashes": [
|
||||
"sha256:00573dfa755d0703ab84bb23cb6ecf97bb683c34b340d4df76651f97b0bab068",
|
||||
"sha256:092049280f2848d2ba1b57b71fe04881762a220a97b65288bcb0968bb199ec30",
|
||||
"sha256:0cbd27b4d3718b5ec74fc65ffa53c78d34c65c6fd9411b8352d2a4f855220cf1",
|
||||
"sha256:17fc7e16d0c81f833a138818a30f366696653d521febc8e892858041c4d88785",
|
||||
"sha256:19577dfeb70e8a67249ba92c8ad20589a1a2d86a8d693647fa8385408a4c17b0",
|
||||
"sha256:207aa914576b1181597a1516e1b90599dc690c095343ae281b0772e44945e6a4",
|
||||
"sha256:219a7db5ed53e523eb4a4769f13105118b6d5b04ed169a283c9775af221e231f",
|
||||
"sha256:2b50ea79849e46b5f4f2b0247a3687505d32d161eeb16a75f6f7e6cd81936e43",
|
||||
"sha256:5903d38362b6c716e66bbe470f190579c530a5baf03dbc8500e5c2357aa569a5",
|
||||
"sha256:5c24903675e271bd688c6e9e7df5775ac6b168feb87dbe0e4bcc90805f21b28f",
|
||||
"sha256:5ef6bc5ed98139e084f4e91100f2b098a0cd3493d4e76f9d6b3f7b95d7ad0f06",
|
||||
"sha256:61b55ae3c23a126a788b33ffb18f37d6668e79a05e756588d9e4d4be7246ab1c",
|
||||
"sha256:63ddb992931a5e616c87d3d89f5a58db086e617548005c7f9059fac68c03a5cc",
|
||||
"sha256:6943da9c09870490dcfd50c4909c0cc19f434fa6948f61282dc9cb07bcf08160",
|
||||
"sha256:6ad40f85c1207803d581d5d75e9ea25327cd524925699a83dfc03bf8e4ba72b7",
|
||||
"sha256:6b44433a79bdd7af0e3337bd7bbcf53dd1f9b0fa66bf21bcb756060ce32a96c1",
|
||||
"sha256:6bbaa245015d933a4172395baad7874373f162955d73612f0b66b6c2c33b6366",
|
||||
"sha256:7007227f4ea85b40a2f5e5a244479f6a6dfcf906db9b55e812a814a8f0e2c28d",
|
||||
"sha256:74884a0aec1f1609190ec8b34b5d58fb3b5353cf22b96161e13e0e835f13518f",
|
||||
"sha256:7d25fe5571ddb16369054f54cdd883f23de9941476d97f2b92eb6d7d83afe22d",
|
||||
"sha256:7e162bdc5e3baad26b2262240be7d2bab36991d85a6a556e48b9dfb402370261",
|
||||
"sha256:814d62678dc3a30f4aa081982d830b7c342cf230ffc9d030b020cb154eeebf9e",
|
||||
"sha256:8878a34c5313ee52e20aa50b03138af8d472bae465710fb954d133a9bfd3c38d",
|
||||
"sha256:a66a0d94e5b081d5d695e66d6667e91e74d79e273eee95c1747717ba9cb70792",
|
||||
"sha256:a69f5cbf4addcfdf03dda564a671040127a6b7c34cf9fe4973582e68441b63fa",
|
||||
"sha256:b00f9f0c334d07709d3f73a7cb8ae63c6ca1a90c790a63b5e7effa666ef96021",
|
||||
"sha256:b6ed71e4a7b4690447b626f499d978aa13197a0e592950e5d7020308f6054698",
|
||||
"sha256:bdf5041e5851526e885af579d2f455348dba68d74f14a32781933569a327fddf",
|
||||
"sha256:be034360dd34e62608419f86e799c97d389c10a0e677a25f236a971b2f40dac9",
|
||||
"sha256:cc8f590a5eed30b314ae6b0232d925519ade433f663de79cc3783e4b10d662ba",
|
||||
"sha256:cd7a318a15fe6cc4584bf3c4426f092ed08c0fd012cf2a9173114234fe193e11",
|
||||
"sha256:cf19b5f63a59c20306e034e691402b02055c8f4e38bf6792c23cad489162a642",
|
||||
"sha256:cfc781ce442ec407c841e9aa51d0e1024f72b6ec34caa8fdb6ef9576d549acf2",
|
||||
"sha256:dea9f6f8633571e18bc20cad83603072e697103a567f4b0738d52dd0211b4527",
|
||||
"sha256:e4a86a1d5eb2cce83c5972b3930c7c1eac81ab3508464345e2b8e54f119d5505",
|
||||
"sha256:e7106374d4a74ed9ff00c46cc00f0a9f06a0775f8868e423f85d4464d2333679",
|
||||
"sha256:e98a8a585b5668aa9e34d10f7785abf9545fe72663b4bfc16c99a115185ae6a5",
|
||||
"sha256:f64840e68483316eb58d82c376ad3585ca995e69e33b230436de0cdddf7363f9",
|
||||
"sha256:f8f4b0a9e6683e43889852130595c8854d8ae237f2324a053cdd884de936aa9b",
|
||||
"sha256:fc45a53219ed30a7f670a6d8c98527af0020e6fd4ee4c0a8fb59f147f06d816c"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.3.5"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -218,8 +218,6 @@ TIME_ZONE = 'Europe/London'
|
||||
|
||||
FORMAT_MODULE_PATH = 'PyRIGS.formats'
|
||||
|
||||
USE_I18N = True
|
||||
|
||||
USE_L10N = True
|
||||
|
||||
USE_TZ = True
|
||||
@@ -264,3 +262,10 @@ TERMS_OF_HIRE_URL = "http://www.nottinghamtec.co.uk/terms.pdf"
|
||||
AUTHORISATION_NOTIFICATION_ADDRESS = 'productions@nottinghamtec.co.uk'
|
||||
|
||||
DEFAULT_AUTO_FIELD = 'django.db.models.AutoField'
|
||||
|
||||
SECURE_HSTS_SECONDS = 3600
|
||||
SECURE_HSTS_INCLUDE_SUBDOMAINS = True
|
||||
SECURE_CONTENT_TYPE_NOSNIFF = True
|
||||
SESSION_COOKIE_SECURE = env('SESSION_COOKIE_SECURE_ENABLED', True)
|
||||
CSRF_COOKIE_SECURE = env('CSRF_COOKIE_SECURE_ENABLED', True)
|
||||
SECURE_HSTS_PRELOAD = True
|
||||
|
||||
@@ -63,7 +63,7 @@ def screenshot_failure(func):
|
||||
if not pathlib.Path("screenshots").is_dir():
|
||||
os.mkdir("screenshots")
|
||||
self.driver.save_screenshot(screenshot_file)
|
||||
print("Error in test {} is at path {}".format(screenshot_name, screenshot_file), file=sys.stderr)
|
||||
print(f"Error in test {screenshot_name} is at path {screenshot_file}", file=sys.stderr)
|
||||
raise e
|
||||
|
||||
return wrapper_func
|
||||
|
||||
@@ -59,8 +59,8 @@ class TestSampleDataGenerator(TestCase):
|
||||
assert Asset.objects.all().count() > 50
|
||||
assert Event.objects.all().count() > 100
|
||||
call_command('deleteSampleData')
|
||||
assert Asset.objects.all().count() == 0
|
||||
assert Event.objects.all().count() == 0
|
||||
assert not Asset.objects.all().exists()
|
||||
assert not Event.objects.all().exists()
|
||||
|
||||
|
||||
@override_settings(DEBUG=True)
|
||||
@@ -76,9 +76,9 @@ def test_unauthenticated(client): # Nothing should be available to the unauthen
|
||||
assertTemplateUsed(response, 'login_redirect.html')
|
||||
else:
|
||||
if "embed" in str(url):
|
||||
expected_url = "{0}?next={1}".format(reverse('login_embed'), request_url)
|
||||
expected_url = f"{reverse('login_embed')}?next={request_url}"
|
||||
else:
|
||||
expected_url = "{0}?next={1}".format(reverse('login'), request_url)
|
||||
expected_url = f"{reverse('login')}?next={request_url}"
|
||||
assertRedirects(response, expected_url)
|
||||
call_command('deleteSampleData')
|
||||
|
||||
|
||||
@@ -48,7 +48,7 @@ class Index(generic.TemplateView): # Displays the current rig count along with
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['rig_count'] = models.Event.objects.rig_count()
|
||||
context['now'] = models.Event.objects.events_in_bounds(timezone.now(), timezone.now())
|
||||
context['now'] = models.Event.objects.events_in_bounds(timezone.now(), timezone.now()).exclude(dry_hire=True).exclude(status=models.Event.CANCELLED)
|
||||
return context
|
||||
|
||||
|
||||
@@ -135,10 +135,11 @@ class SecureAPIRequest(generic.View):
|
||||
query = reduce(operator.and_, queries)
|
||||
objects = self.models[model].objects.filter(query)
|
||||
for o in objects:
|
||||
name = o.display_name if hasattr(o, 'display_name') else o.name
|
||||
data = {
|
||||
'pk': o.pk,
|
||||
'value': o.pk,
|
||||
'text': o.name,
|
||||
'text': name,
|
||||
}
|
||||
try: # See if there is a valid update URL
|
||||
data['update'] = reverse(f"{model}_update", kwargs={'pk': o.pk})
|
||||
@@ -183,7 +184,7 @@ class ModalURLMixin:
|
||||
url = reverse_lazy('closemodal')
|
||||
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[0]['update_url']='" + update_url + "'")
|
||||
messages.info(self.request, f"modalobject[0]['update_url']='{update_url}'")
|
||||
else:
|
||||
url = reverse_lazy(detail, kwargs={
|
||||
'pk': self.object.pk,
|
||||
|
||||
@@ -11,8 +11,9 @@ For setup information and other such helpful stuff check the [Wiki](https://gith
|
||||
- PyRIGS: Base app, stores 'global' information
|
||||
- RIGS: Rigboard stuff - event calendar etc
|
||||
- assets: Database of our kit, testing data etc
|
||||
- training: Logs in-house training within various "departments" (sound, lighting etc).
|
||||
- versioning: Our custom logic built on top of django-reversion. Semi-modular.
|
||||
- users: Our custom logic for registration and profiles. Semi-modular.
|
||||
- training: SoonTM
|
||||
|
||||
|
||||
[](https://forthebadge.com) [](https://forthebadge.com)
|
||||
|
||||
@@ -131,7 +131,7 @@ class BaseClientEventAuthorisationForm(forms.ModelForm):
|
||||
def clean(self):
|
||||
if self.cleaned_data.get('amount') != self.instance.event.total:
|
||||
self.add_error('amount', 'The amount authorised must equal the total for the event (inc VAT).')
|
||||
return super(BaseClientEventAuthorisationForm, self).clean()
|
||||
return super().clean()
|
||||
|
||||
class Meta:
|
||||
abstract = True
|
||||
@@ -179,7 +179,7 @@ class EventRiskAssessmentForm(forms.ModelForm):
|
||||
unexpected_values.append(f"<li>{self._meta.model._meta.get_field(field).help_text}</li>")
|
||||
if len(unexpected_values) > 0 and not self.cleaned_data.get('supervisor_consulted'):
|
||||
raise forms.ValidationError(f"Your answers to these questions: <ul>{''.join([str(elem) for elem in unexpected_values])}</ul> require consulting with a supervisor.", code='unusual_answers')
|
||||
return super(EventRiskAssessmentForm, self).clean()
|
||||
return super().clean()
|
||||
|
||||
class Meta:
|
||||
model = models.RiskAssessment
|
||||
@@ -195,8 +195,6 @@ class EventChecklistForm(forms.ModelForm):
|
||||
if field.__class__ == forms.NullBooleanField:
|
||||
# Only display yes/no to user, the 'none' is only ever set in the background
|
||||
field.widget = forms.CheckboxInput()
|
||||
# Parsed from incoming form data by clean, then saved into models when the form is saved
|
||||
items = {}
|
||||
|
||||
related_models = {
|
||||
'venue': models.Venue,
|
||||
@@ -216,6 +214,11 @@ class PowerTestRecordForm(forms.ModelForm):
|
||||
# Only display yes/no to user, the 'none' is only ever set in the background
|
||||
field.widget = forms.CheckboxInput()
|
||||
|
||||
related_models = {
|
||||
'venue': models.Venue,
|
||||
'power_mic': models.Profile,
|
||||
}
|
||||
|
||||
class Meta:
|
||||
model = models.PowerTestRecord
|
||||
fields = '__all__'
|
||||
|
||||
53
RIGS/migrations/0049_auto_20230529_1123.py
Normal file
53
RIGS/migrations/0049_auto_20230529_1123.py
Normal file
@@ -0,0 +1,53 @@
|
||||
# Generated by Django 3.2.19 on 2023-05-29 10:23
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('RIGS', '0048_auto_20230518_1256'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='powertestrecord',
|
||||
name='fd_earth_fault',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, help_text='Earth Fault Loop Impedance (Z<small>S</small>) / Ω', max_digits=6, null=True, verbose_name='Earth Fault Loop Impedance'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powertestrecord',
|
||||
name='fd_pssc',
|
||||
field=models.IntegerField(blank=True, help_text='Prospective Short Circuit Current / A', null=True, verbose_name='PSCC'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powertestrecord',
|
||||
name='w1_earth_fault',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, help_text='Earth Fault Loop Impedance (Z<small>S</small>) / Ω', max_digits=6, null=True, verbose_name='Earth Fault Loop Impedance'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powertestrecord',
|
||||
name='w1_voltage',
|
||||
field=models.IntegerField(blank=True, help_text='Voltage / V', null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powertestrecord',
|
||||
name='w2_earth_fault',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, help_text='Earth Fault Loop Impedance (Z<small>S</small>) / Ω', max_digits=6, null=True, verbose_name='Earth Fault Loop Impedance'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powertestrecord',
|
||||
name='w2_voltage',
|
||||
field=models.IntegerField(blank=True, help_text='Voltage / V', null=True),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powertestrecord',
|
||||
name='w3_earth_fault',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, help_text='Earth Fault Loop Impedance (Z<small>S</small>) / Ω', max_digits=6, null=True, verbose_name='Earth Fault Loop Impedance'),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='powertestrecord',
|
||||
name='w3_voltage',
|
||||
field=models.IntegerField(blank=True, help_text='Voltage / V', null=True),
|
||||
),
|
||||
]
|
||||
@@ -497,7 +497,7 @@ class Event(models.Model, RevisionMixin):
|
||||
earliest = datetime.datetime.combine(self.start_date, datetime.time(00, 00))
|
||||
tz = pytz.timezone(settings.TIME_ZONE)
|
||||
earliest = tz.localize(earliest)
|
||||
return not self.dry_hire and earliest <= timezone.now()
|
||||
return not self.dry_hire and not self.status == Event.CANCELLED and earliest <= timezone.now()
|
||||
|
||||
objects = EventManager()
|
||||
|
||||
@@ -875,6 +875,9 @@ class EventChecklist(ReviewableModel, RevisionMixin):
|
||||
|
||||
@reversion.register
|
||||
class PowerTestRecord(ReviewableModel, RevisionMixin):
|
||||
earth_fault_text = "Earth Fault Loop Impedance (Z<small>S</small>) / Ω"
|
||||
pssc_text = "Prospective Short Circuit Current / A"
|
||||
|
||||
event = models.ForeignKey('Event', related_name='power_tests', on_delete=models.CASCADE)
|
||||
power_mic = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True, related_name='checklists',
|
||||
verbose_name="Power MIC", on_delete=models.CASCADE, help_text="Who is the Power MIC?")
|
||||
@@ -896,21 +899,21 @@ class PowerTestRecord(ReviewableModel, RevisionMixin):
|
||||
fd_voltage_l2 = models.IntegerField(blank=True, null=True, verbose_name="First Distro Voltage L2-N", help_text="L2 - N")
|
||||
fd_voltage_l3 = models.IntegerField(blank=True, null=True, verbose_name="First Distro Voltage L3-N", help_text="L3 - N")
|
||||
fd_phase_rotation = models.BooleanField(blank=True, null=True, verbose_name="Phase Rotation", help_text="Phase Rotation<br><small>(if required)</small>")
|
||||
fd_earth_fault = models.DecimalField(blank=True, null=True, max_digits=5, decimal_places=2, verbose_name="Earth Fault Loop Impedance", help_text="Earth Fault Loop Impedance (Z<small>S</small>)")
|
||||
fd_pssc = models.IntegerField(blank=True, null=True, verbose_name="PSCC", help_text="Prospective Short Circuit Current")
|
||||
fd_earth_fault = models.DecimalField(blank=True, null=True, max_digits=6, decimal_places=2, verbose_name="Earth Fault Loop Impedance", help_text=earth_fault_text)
|
||||
fd_pssc = models.IntegerField(blank=True, null=True, verbose_name="PSCC", help_text=pssc_text)
|
||||
# Worst case points
|
||||
w1_description = models.CharField(blank=True, default='', max_length=255, help_text="Description")
|
||||
w1_polarity = models.BooleanField(blank=True, null=True, help_text="Polarity Checked?")
|
||||
w1_voltage = models.IntegerField(blank=True, null=True, help_text="Voltage")
|
||||
w1_earth_fault = models.DecimalField(blank=True, null=True, max_digits=5, decimal_places=2, verbose_name="Earth Fault Loop Impedance", help_text="Earth Fault Loop Impedance (Z<small>S</small>)")
|
||||
w1_voltage = models.IntegerField(blank=True, null=True, help_text="Voltage / V")
|
||||
w1_earth_fault = models.DecimalField(blank=True, null=True, max_digits=6, decimal_places=2, verbose_name="Earth Fault Loop Impedance", help_text=earth_fault_text)
|
||||
w2_description = models.CharField(blank=True, default='', max_length=255, help_text="Description")
|
||||
w2_polarity = models.BooleanField(blank=True, null=True, help_text="Polarity Checked?")
|
||||
w2_voltage = models.IntegerField(blank=True, null=True, help_text="Voltage")
|
||||
w2_earth_fault = models.DecimalField(blank=True, null=True, max_digits=5, decimal_places=2, verbose_name="Earth Fault Loop Impedance", help_text="Earth Fault Loop Impedance (Z<small>S</small>)")
|
||||
w2_voltage = models.IntegerField(blank=True, null=True, help_text="Voltage / V")
|
||||
w2_earth_fault = models.DecimalField(blank=True, null=True, max_digits=6, decimal_places=2, verbose_name="Earth Fault Loop Impedance", help_text=earth_fault_text)
|
||||
w3_description = models.CharField(blank=True, default='', max_length=255, help_text="Description")
|
||||
w3_polarity = models.BooleanField(blank=True, null=True, help_text="Polarity Checked?")
|
||||
w3_voltage = models.IntegerField(blank=True, null=True, help_text="Voltage")
|
||||
w3_earth_fault = models.DecimalField(blank=True, null=True, max_digits=5, decimal_places=2, verbose_name="Earth Fault Loop Impedance", help_text="Earth Fault Loop Impedance (Z<small>S</small>)")
|
||||
w3_voltage = models.IntegerField(blank=True, null=True, help_text="Voltage / V")
|
||||
w3_earth_fault = models.DecimalField(blank=True, null=True, max_digits=6, decimal_places=2, verbose_name="Earth Fault Loop Impedance", help_text=earth_fault_text)
|
||||
|
||||
all_rcds_tested = models.BooleanField(blank=True, null=True, help_text="All circuit RCDs tested?<br><small>(using test button)</small>")
|
||||
public_sockets_tested = models.BooleanField(blank=True, null=True, help_text="Public/Performer accessible circuits tested?<br><small>(using socket tester)</small>")
|
||||
@@ -924,6 +927,9 @@ class PowerTestRecord(ReviewableModel, RevisionMixin):
|
||||
def __str__(self):
|
||||
return f"{self.pk} - {self.event}"
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('pt_detail', kwargs={'pk': self.pk})
|
||||
|
||||
@property
|
||||
def activity_feed_string(self):
|
||||
return str(self.event)
|
||||
|
||||
@@ -209,7 +209,7 @@
|
||||
<div class="col-sm-9 col-md-7 col-lg-8">
|
||||
<select id="{{ form.venue.id_for_label }}" name="{{ form.venue.name }}" class="selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='venue' %}">
|
||||
{% if venue %}
|
||||
<option value="{{form.venue.value}}" selected="selected" data-update_url="{% url 'venue_update' form.venue.value %}">{{ venue }}</option>
|
||||
<option value="{{venue.id}}" selected="selected" data-update_url="{% url 'venue_update' venue.id %}">{{ venue }}</option>
|
||||
{% endif %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -9,6 +9,8 @@
|
||||
<div class="col-12 text-right my-3">
|
||||
{% button 'edit' url='ec_edit' pk=object.pk %}
|
||||
{% button 'view' url='event_detail' pk=object.event.pk text="Event" %}
|
||||
<a href="{% url 'event_pt' object.event.pk %}" class="btn btn-info"><span class="fas fa-paperclip"></span> <span
|
||||
class="hidden-xs">Create Power Test</span></a>
|
||||
{% include 'partials/review_status.html' with perm=perms.RIGS.review_eventchecklist review='ec_review' %}
|
||||
</div>
|
||||
</div>
|
||||
@@ -71,6 +73,8 @@
|
||||
<div class="col-12 text-right">
|
||||
{% button 'edit' url='ec_edit' pk=object.pk %}
|
||||
{% button 'view' url='event_detail' pk=object.pk text="Event" %}
|
||||
<a href="{% url 'event_pt' object.event.pk %}" class="btn btn-info"><span class="fas fa-paperclip"></span> <span
|
||||
class="hidden-xs">Create Power Test</span></a>
|
||||
{% include 'partials/review_status.html' with perm=perms.RIGS.review_eventchecklist review='ec_review' %}
|
||||
</div>
|
||||
<div class="col-12 text-right">
|
||||
|
||||
@@ -24,7 +24,7 @@
|
||||
{% block content %}
|
||||
<div class="col-12">
|
||||
{% include 'form_errors.html' %}
|
||||
|
||||
|
||||
<form role="form" method="POST" action="{% if edit %}{% url 'ec_edit' pk=object.pk %}{% else %}{% url 'event_ec' pk=event.pk %}{% endif %}">
|
||||
<input type="hidden" name="{{ form.event.name }}" id="{{ form.event.id_for_label }}"
|
||||
value="{{event.pk}}"/>
|
||||
@@ -59,8 +59,6 @@
|
||||
<select id="{{ form.venue.id_for_label }}" name="{{ form.venue.name }}" class="selectpicker" data-live-search="true" data-sourceurl="{% url 'api_secure' model='venue' %}">
|
||||
{% if venue %}
|
||||
<option value="{{venue.pk}}" selected="selected">{{ venue.name }}</option>
|
||||
{% elif event.venue %}
|
||||
<option value="{{event.venue.pk}}" selected="selected">{{ event.venue.name }}</option>
|
||||
{% endif %}
|
||||
</select>
|
||||
</div>
|
||||
|
||||
@@ -86,7 +86,7 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row" rowspan="2">Voltage<br><small>(cube meter)</small></th>
|
||||
<th scope="row" rowspan="2">Voltage<br><small>(cube meter)</small> / V</th>
|
||||
<th>{{ object|help_text:'fd_voltage_l1' }}</th>
|
||||
<th>{{ object|help_text:'fd_voltage_l2' }}</th>
|
||||
<th>{{ object|help_text:'fd_voltage_l3' }}</th>
|
||||
|
||||
@@ -51,22 +51,18 @@
|
||||
<div class="form-group form-row" id="{{ form.power_mic.id_for_label }}-group">
|
||||
<label for="{{ form.power_mic.id_for_label }}"
|
||||
class="col-4 col-form-label">{{ form.power_mic.help_text }}</label>
|
||||
<select id="{{ form.power_mic.id_for_label }}" name="{{ form.power_mic.name }}" class="form-control selectpicker col-8" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials" required="true">
|
||||
<select id="{{ form.power_mic.id_for_label }}" name="{{ form.power_mic.name }}" class="selectpicker col-8" data-live-search="true" data-sourceurl="{% url 'api_secure' model='profile' %}?fields=first_name,last_name,initials" required="true">
|
||||
{% if power_mic %}
|
||||
<option value="{{power_mic.pk}}" selected="selected">{{ power_mic.name }}</option>
|
||||
{% elif event.riskassessment.power_mic %}
|
||||
<option value="{{event.riskassessment.power_mic.pk}}" selected="selected">{{ event.riskassessment.power_mic.name }}</option>
|
||||
{% endif %}
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group form-row" id="{{ form.venue.id_for_label }}-group">
|
||||
<label for="{{ form.venue.id_for_label }}"
|
||||
class="col-4 col-form-label">{{ form.venue.label }}</label>
|
||||
<select id="{{ form.venue.id_for_label }}" name="{{ form.venue.name }}" class="form-control selectpicker col-8" data-live-search="true" data-sourceurl="{% url 'api_secure' model='venue' %}">
|
||||
<select id="{{ form.venue.id_for_label }}" name="{{ form.venue.name }}" class="selectpicker col-8" data-live-search="true" data-sourceurl="{% url 'api_secure' model='venue' %}">
|
||||
{% if venue %}
|
||||
<option value="{{venue.pk}}" selected="selected">{{ venue.name }}</option>
|
||||
{% elif event.venue %}
|
||||
<option value="{{event.venue.pk}}" selected="selected">{{ event.venue.name }}</option>
|
||||
{% endif %}
|
||||
</select>
|
||||
</div>
|
||||
@@ -119,7 +115,7 @@
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row" rowspan="2">Voltage<br><small>(cube meter)</small></th>
|
||||
<th scope="row" rowspan="2">Voltage<br><small>(cube meter)</small> / V</th>
|
||||
<th class="text-center">{{ form.fd_voltage_l1.help_text }}</th>
|
||||
<th class="text-center">{{ form.fd_voltage_l2.help_text }}</th>
|
||||
<th class="text-center">{{ form.fd_voltage_l3.help_text }}</th>
|
||||
|
||||
@@ -25,7 +25,7 @@
|
||||
});
|
||||
$('input[type=radio][name=outside], input[type=radio][name=generators], input[type=radio][name=other_companies_power], input[type=radio][name=nonstandard_equipment_power], input[type=radio][name=multiple_electrical_environments]').change(function() {
|
||||
$('#{{ form.power_notes.id_for_label }}').prop('required', parseBool(this.value));
|
||||
$('#{{ form.power_plan.id_for_label }}').prop('required', parseBool(this.value));
|
||||
//$('#{{ form.power_plan.id_for_label }}').prop('required', parseBool(this.value));
|
||||
});
|
||||
$('input[type=radio][name=special_structures]').change(function() {
|
||||
$('#{{ form.persons_responsible_structures.id_for_label }}').prop('hidden', !parseBool(this.value)).prop('required', parseBool(this.value));
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
{% endif %}
|
||||
{% endif %}
|
||||
{% if not event.dry_hire %}
|
||||
{% if event.has_checklist %}
|
||||
{% if event.riskassessment %}
|
||||
<a href="{{ event.riskassessment.get_absolute_url }}"><span class="badge badge-success">RA: <span class="fas fa-check{% if event.riskassessment.reviewed_by %}-double{%endif%}"></span></a>
|
||||
{% else %}
|
||||
<span class="badge badge-danger">RA: <span class="fas fa-times"></span></span>
|
||||
|
||||
@@ -171,7 +171,7 @@ def title_spaced(string):
|
||||
@register.filter(needs_autoescape=True)
|
||||
def namewithnotes(obj, url, autoescape=True):
|
||||
if hasattr(obj, 'notes') and obj.notes is not None and len(obj.notes) > 0:
|
||||
return mark_safe(obj.name + " <a href='{}'><span class='fas fa-sticky-note'></span></a>".format(reverse(url, kwargs={'pk': obj.pk})))
|
||||
return mark_safe(obj.name + f" <a href='{reverse(url, kwargs={'pk': obj.pk})}'><span class='fas fa-sticky-note'></span></a>")
|
||||
else:
|
||||
return obj.name
|
||||
|
||||
@@ -183,7 +183,7 @@ def linkornone(target, namespace=None, autoescape=True):
|
||||
link = namespace + "://" + target
|
||||
else:
|
||||
link = target
|
||||
return mark_safe("<a href='{}' target='_blank'><span class='overflow-ellipsis'>{}</span></a>".format(link, str(target)))
|
||||
return mark_safe(f"<a href='{link}' target='_blank'><span class='overflow-ellipsis'>{target}</span></a>")
|
||||
else:
|
||||
return "None"
|
||||
|
||||
|
||||
@@ -114,7 +114,7 @@ class CreateEvent(FormPage):
|
||||
}
|
||||
|
||||
def select_event_type(self, type_name):
|
||||
self.find_element(By.XPATH, '//button[.="{}"]'.format(type_name)).click()
|
||||
self.find_element(By.XPATH, f'//button[.="{type_name}"]').click()
|
||||
|
||||
def item_row(self, ID):
|
||||
return rigs_regions.ItemRow(self, self.find_element(By.ID, "item-" + ID))
|
||||
|
||||
@@ -259,7 +259,7 @@ class TestPrintPaperwork(TestCase):
|
||||
|
||||
def test_login_redirect(client, django_user_model):
|
||||
request_url = reverse('event_embed', kwargs={'pk': 1})
|
||||
expected_url = "{0}?next={1}".format(reverse('login_embed'), request_url)
|
||||
expected_url = f"{reverse('login_embed')}?next={request_url}"
|
||||
|
||||
# Request the page and check it redirects
|
||||
response = client.get(request_url, follow=True)
|
||||
@@ -372,7 +372,8 @@ def test_ra_redirect(admin_client, admin_user, ra):
|
||||
|
||||
|
||||
class TestMarkdownTemplateTags(TestCase):
|
||||
markdown = open(os.path.join(settings.BASE_DIR, "RIGS/tests/sample.md")).read()
|
||||
with open(os.path.join(settings.BASE_DIR, "RIGS/tests/sample.md"), encoding="utf-8") as f:
|
||||
markdown = f.read()
|
||||
|
||||
def test_html_safe(self):
|
||||
html = markdown_filter(self.markdown)
|
||||
|
||||
@@ -13,31 +13,24 @@ from django.shortcuts import redirect
|
||||
|
||||
|
||||
class HSCreateView(generic.CreateView):
|
||||
def get_form(self, **kwargs):
|
||||
form = super().get_form(**kwargs)
|
||||
epk = self.kwargs.get('pk')
|
||||
event = models.Event.objects.get(pk=epk)
|
||||
form.instance.event = event
|
||||
return form
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
epk = self.kwargs.get('pk')
|
||||
event = models.Event.objects.get(pk=epk)
|
||||
event = models.Event.objects.get(pk=self.kwargs.get('pk'))
|
||||
context['event'] = event
|
||||
context['page_title'] = f'Create {self.model.__name__} for Event {event.display_id}'
|
||||
get_related(context['form'], context)
|
||||
return context
|
||||
|
||||
|
||||
class MarkReviewed(generic.View):
|
||||
def get(self, *args, **kwargs):
|
||||
class MarkReviewed(generic.RedirectView):
|
||||
def get_redirect_url(self, *args, **kwargs):
|
||||
obj = apps.get_model('RIGS', kwargs.get('model')).objects.get(pk=kwargs.get('pk'))
|
||||
with reversion.create_revision():
|
||||
reversion.set_user(self.request.user)
|
||||
obj.reviewed_by = self.request.user
|
||||
obj.reviewed_at = timezone.now()
|
||||
obj.save()
|
||||
return HttpResponseRedirect(reverse('hs_list'))
|
||||
return self.request.META.get('HTTP_REFERER', reverse('hs_list'))
|
||||
|
||||
|
||||
class EventRiskAssessmentCreate(HSCreateView):
|
||||
@@ -55,11 +48,17 @@ class EventRiskAssessmentCreate(HSCreateView):
|
||||
if ra is not None:
|
||||
return HttpResponseRedirect(reverse('ra_edit', kwargs={'pk': ra.pk}))
|
||||
|
||||
return super(EventRiskAssessmentCreate, self).get(self)
|
||||
return super().get(self)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('ra_detail', kwargs={'pk': self.object.pk})
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
if context['event'].mic:
|
||||
context['power_mic'] = context['event'].mic
|
||||
return context
|
||||
|
||||
|
||||
class EventRiskAssessmentEdit(generic.UpdateView):
|
||||
model = models.RiskAssessment
|
||||
@@ -74,7 +73,7 @@ class EventRiskAssessmentEdit(generic.UpdateView):
|
||||
return reverse('ra_detail', kwargs={'pk': self.object.pk})
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(EventRiskAssessmentEdit, self).get_context_data(**kwargs)
|
||||
context = super().get_context_data(**kwargs)
|
||||
rpk = self.kwargs.get('pk')
|
||||
ra = models.RiskAssessment.objects.get(pk=rpk)
|
||||
context['event'] = ra.event
|
||||
@@ -89,7 +88,7 @@ class EventRiskAssessmentDetail(generic.DetailView):
|
||||
template_name = 'hs/risk_assessment_detail.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(EventRiskAssessmentDetail, self).get_context_data(**kwargs)
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['page_title'] = f"Risk Assessment for Event <a href='{self.object.event.get_absolute_url()}'>{self.object.event.display_id} {self.object.event.name}</a>"
|
||||
return context
|
||||
|
||||
@@ -99,7 +98,7 @@ class EventChecklistDetail(generic.DetailView):
|
||||
template_name = 'hs/event_checklist_detail.html'
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(EventChecklistDetail, self).get_context_data(**kwargs)
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['page_title'] = f"Event Checklist for Event <a href='{self.object.event.get_absolute_url()}'>{self.object.event.display_id} {self.object.event.name}</a>"
|
||||
return context
|
||||
|
||||
@@ -117,7 +116,7 @@ class EventChecklistEdit(generic.UpdateView):
|
||||
return reverse('ec_detail', kwargs={'pk': self.object.pk})
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(EventChecklistEdit, self).get_context_data(**kwargs)
|
||||
context = super().get_context_data(**kwargs)
|
||||
pk = self.kwargs.get('pk')
|
||||
ec = models.EventChecklist.objects.get(pk=pk)
|
||||
context['event'] = ec.event
|
||||
@@ -136,19 +135,22 @@ class EventChecklistCreate(HSCreateView):
|
||||
def get(self, *args, **kwargs):
|
||||
epk = kwargs.get('pk')
|
||||
event = models.Event.objects.get(pk=epk)
|
||||
|
||||
# Check if RA exists
|
||||
ra = models.RiskAssessment.objects.filter(event=event).first()
|
||||
|
||||
if ra is None:
|
||||
messages.error(self.request, f'A Risk Assessment must exist prior to creating any Event Checklists for {event}! Please create one now.')
|
||||
return HttpResponseRedirect(reverse('event_ra', kwargs={'pk': epk}))
|
||||
|
||||
return super(EventChecklistCreate, self).get(self)
|
||||
return super().get(self)
|
||||
|
||||
def get_success_url(self):
|
||||
return reverse('ec_detail', kwargs={'pk': self.object.pk})
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
if context['event'].venue:
|
||||
context['venue'] = context['event'].venue
|
||||
return context
|
||||
|
||||
|
||||
class PowerTestDetail(generic.DetailView):
|
||||
model = models.PowerTestRecord
|
||||
@@ -179,7 +181,7 @@ class PowerTestEdit(generic.UpdateView):
|
||||
context['event'] = ec.event
|
||||
context['edit'] = True
|
||||
context['page_title'] = f'Edit Power Test Record for Event {ec.event.display_id}'
|
||||
# get_related(context['form'], context)
|
||||
get_related(context['form'], context)
|
||||
return context
|
||||
|
||||
|
||||
@@ -191,7 +193,6 @@ class PowerTestCreate(HSCreateView):
|
||||
def get(self, *args, **kwargs):
|
||||
epk = kwargs.get('pk')
|
||||
event = models.Event.objects.get(pk=epk)
|
||||
|
||||
# Check if RA exists
|
||||
ra = models.RiskAssessment.objects.filter(event=event).first()
|
||||
|
||||
@@ -204,6 +205,14 @@ class PowerTestCreate(HSCreateView):
|
||||
def get_success_url(self):
|
||||
return reverse('pt_detail', kwargs={'pk': self.object.pk})
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
if context['event'].venue:
|
||||
context['venue'] = context['event'].venue
|
||||
if context['event'].riskassessment.power_mic:
|
||||
context['power_mic'] = context['event'].riskassessment.power_mic
|
||||
return context
|
||||
|
||||
|
||||
class HSList(generic.ListView):
|
||||
paginate_by = 20
|
||||
@@ -211,10 +220,10 @@ class HSList(generic.ListView):
|
||||
template_name = 'hs/hs_list.html'
|
||||
|
||||
def get_queryset(self):
|
||||
return models.Event.objects.all().exclude(status=models.Event.CANCELLED).order_by('-start_date').select_related('riskassessment').prefetch_related('checklists')
|
||||
return models.Event.objects.all().exclude(status=models.Event.CANCELLED).exclude(dry_hire=True).order_by('-start_date').select_related('riskassessment').prefetch_related('checklists')
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(HSList, self).get_context_data(**kwargs)
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['page_title'] = 'H&S Overview'
|
||||
return context
|
||||
|
||||
|
||||
18
assets/migrations/0028_alter_asset_length.py
Normal file
18
assets/migrations/0028_alter_asset_length.py
Normal file
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 3.2.19 on 2023-05-24 22:03
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('assets', '0027_asset_nickname'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='asset',
|
||||
name='length',
|
||||
field=models.DecimalField(blank=True, decimal_places=2, help_text='m', max_digits=10, null=True),
|
||||
),
|
||||
]
|
||||
@@ -135,7 +135,7 @@ class Asset(models.Model, RevisionMixin):
|
||||
# Cable assets
|
||||
is_cable = models.BooleanField(default=False)
|
||||
cable_type = models.ForeignKey(to=CableType, blank=True, null=True, on_delete=models.SET_NULL)
|
||||
length = models.DecimalField(decimal_places=1, max_digits=10,
|
||||
length = models.DecimalField(decimal_places=2, max_digits=10,
|
||||
blank=True, null=True, help_text='m')
|
||||
csa = models.DecimalField(decimal_places=2, max_digits=10,
|
||||
blank=True, null=True, help_text='mm²')
|
||||
@@ -192,5 +192,5 @@ class Asset(models.Model, RevisionMixin):
|
||||
return str(self.asset_id)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
def display_name(self):
|
||||
return f"{self.display_id} | {self.description}"
|
||||
|
||||
@@ -35,6 +35,11 @@
|
||||
function onAuditClick(assetID) {
|
||||
$('#' + assetID).remove();
|
||||
}
|
||||
$('#modal').on('hidden.bs.modal', function (e) {
|
||||
searchbar = document.getElementById('id_q');
|
||||
searchbar.value = "";
|
||||
setTimeout(searchbar.focus(), 2000);
|
||||
})
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
|
||||
@@ -12,7 +12,6 @@
|
||||
{{ block.super }}
|
||||
<script src="{% static 'js/selects.js' %}"></script>
|
||||
<script src="{% static 'js/easymde.min.js' %}"></script>
|
||||
<script src="{% static 'js/interaction.js' %}"></script>
|
||||
{% endblock %}
|
||||
|
||||
{% block js %}
|
||||
@@ -35,9 +34,10 @@
|
||||
$(document).find(".selectpicker").selectpicker().each(function(){initPicker($(this))});
|
||||
});
|
||||
</script>
|
||||
<script src="{% static "js/tooltip.js" %}"></script>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
setupMDE('#id_comments');
|
||||
$(function () {
|
||||
$('[data-toggle="tooltip"]').tooltip();
|
||||
});
|
||||
</script>
|
||||
{% endblock %}
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
</thead>
|
||||
<tbody id="asset_table_body">
|
||||
{% for item in object_list %}
|
||||
<tr class="table-{{ item.status.display_class|default:'' }} assetRow">
|
||||
<tr class="table-{{ item.status.display_class|default:'' }} assetRow" id="{{ item.asset_id }}">
|
||||
<th scope="row" class="align-middle"><a class="assetID" href="{% url 'asset_detail' item.asset_id %}">{{ item.asset_id }}</a></th>
|
||||
<td class="assetDesc"><span class="text-truncate d-inline-block align-middle">{{ item.description }}</span></td>
|
||||
<td class="assetCategory align-middle">{{ item.category }}</td>
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
<label for="{{ form.purchase_price.id_for_label }}">Purchase Price</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend"><span class="input-group-text">£</span></div>
|
||||
{% render_field form.purchase_price|add_class:'form-control' value=object.purchase_price %}
|
||||
{% render_field form.purchase_price|add_class:'form-control'|set_data:"toggle:tooltip" value=object.purchase_price title="Ex. VAT" %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -42,7 +42,7 @@
|
||||
<label for="{{ form.salvage_value.id_for_label }}">Replacement Cost</label>
|
||||
<div class="input-group">
|
||||
<div class="input-group-prepend"><span class="input-group-text">£</span></div>
|
||||
{% render_field form.replacement_cost|add_class:'form-control' value=object.replacement_cost %}
|
||||
{% render_field form.replacement_cost|add_class:'form-control'|set_data:"toggle:tooltip" value=object.replacement_cost title="Ex. VAT" %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -77,7 +77,7 @@ class AssetForm(FormPage):
|
||||
'description': (regions.TextBox, (By.ID, 'id_description')),
|
||||
'is_cable': (regions.CheckBox, (By.ID, 'id_is_cable')),
|
||||
'serial_number': (regions.TextBox, (By.ID, 'id_serial_number')),
|
||||
'comments': (regions.SimpleMDETextArea, (By.ID, 'id_comments')),
|
||||
'comments': (regions.TextBox, (By.ID, 'id_comments')),
|
||||
'purchase_price': (regions.TextBox, (By.ID, 'id_purchase_price')),
|
||||
'replacement_cost': (regions.TextBox, (By.ID, 'id_replacement_cost')),
|
||||
'date_acquired': (regions.DatePicker, (By.ID, 'id_date_acquired')),
|
||||
|
||||
1
package-lock.json
generated
1
package-lock.json
generated
@@ -5,6 +5,7 @@
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "PyRIGS",
|
||||
"version": "1.0.0",
|
||||
"license": "Custom",
|
||||
"dependencies": {
|
||||
|
||||
@@ -6,11 +6,6 @@ function setupItemTable(items_json) {
|
||||
newitem = -1;
|
||||
}
|
||||
|
||||
function nl2br(str, is_xhtml) {
|
||||
var breakTag = (is_xhtml || typeof is_xhtml === 'undefined') ? '<br />' : '<br>';
|
||||
return (str + '').replace(/([^>\r\n]?)(\r\n|\n\r|\r|\n)/g, '$1'+ breakTag +'$2');
|
||||
}
|
||||
|
||||
function escapeHtml(str) {
|
||||
return $('<div/>').text(str).html();
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
e.preventDefault();
|
||||
data = $(this).serialize();
|
||||
action = $(this).attr('action');
|
||||
console.log(action)
|
||||
$.post(action, data, function(resp) {
|
||||
$('#modal').html(resp);
|
||||
});
|
||||
|
||||
@@ -1,15 +1,15 @@
|
||||
{% load widget_tweaks %}
|
||||
{% load title_spaced from filters %}
|
||||
{% spaceless %}
|
||||
<label for="{{ field.id_for_label }}" {% if col %}class="col-4 col-form-label"{% endif %}>{% if title %}{{ title }}{%else%}{{field.name|title_spaced}}{%endif%}</label>
|
||||
{% if not nolabel %}<label for="{{ field.id_for_label }}" {% if col %}class="col-4 col-form-label"{% endif %}>{% if title %}{{ title }}{%else%}{{field.name|title_spaced}}{%endif%}</label>{%endif%}
|
||||
{% if append or prepend %}
|
||||
<div class="input-group {{col}}">
|
||||
<div class="input-group {{col}} flex-nowrap">
|
||||
{% if prepend %}
|
||||
<div class="input-group-prepend">
|
||||
<span class="input-group-text">{{ prepend }}</span>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% render_field field|add_class:'form-control' %}
|
||||
{% render_field field|add_class:'form-control' style=style %}
|
||||
{% if append %}
|
||||
<div class="input-group-append">
|
||||
<span class="input-group-text">{{ append }}</span>
|
||||
@@ -17,6 +17,6 @@
|
||||
{% endif %}
|
||||
</div>
|
||||
{% else %}
|
||||
{% render_field field|add_class:'form-control' class+=col %}
|
||||
{% render_field field|add_class:'form-control' class+=col style=style %}
|
||||
{% endif %}
|
||||
{% endspaceless %}
|
||||
@@ -105,6 +105,10 @@ class TrainingItem(models.Model):
|
||||
def display_id(self):
|
||||
return f"{self.category.reference_number}.{self.reference_number}"
|
||||
|
||||
@property
|
||||
def display_name(self):
|
||||
return f"{self.display_id} | {self.name}"
|
||||
|
||||
@display_id.filter
|
||||
@classmethod
|
||||
def display_id(cls, lookup, value):
|
||||
@@ -369,7 +373,7 @@ class TrainingLevelQualification(models.Model, RevisionMixin):
|
||||
return str(self)
|
||||
|
||||
def get_absolute_url(self):
|
||||
return reverse('trainee_detail', kwargs={'pk': self.trainee.pk})
|
||||
return reverse('trainee_detail', kwargs={'pk': self.trainee_id})
|
||||
|
||||
class Meta:
|
||||
unique_together = ["trainee", "level"]
|
||||
|
||||
@@ -43,7 +43,7 @@ def confirm_button(user, trainee, level):
|
||||
if level.user_has_requirements(trainee):
|
||||
string = "<span class='badge badge-warning p-2'>Awaiting Confirmation</span>"
|
||||
if models.Trainee.objects.get(pk=user.pk).is_supervisor or user.has_perm('training.add_traininglevelqualification'):
|
||||
string += "<a class='btn btn-info' href='{}'>Confirm</a>".format(reverse('confirm_level', kwargs={'pk': trainee.pk, 'level_pk': level.pk}))
|
||||
string += f"<a class='btn btn-info' href='{reverse('confirm_level', kwargs={'pk': trainee.pk, 'level_pk': level.pk})}'>Confirm</a>"
|
||||
return mark_safe(string)
|
||||
else:
|
||||
return ""
|
||||
|
||||
@@ -44,7 +44,7 @@ def test_add_qualification(logged_in_browser, live_server, trainee, supervisor,
|
||||
page.submit()
|
||||
assert page.success
|
||||
qualification = models.TrainingItemQualification.objects.get(trainee=trainee, item=training_item)
|
||||
assert qualification.supervisor.pk == supervisor.pk
|
||||
assert qualification.supervisor_id == supervisor.pk
|
||||
assert qualification.date == date
|
||||
assert qualification.notes == "A note"
|
||||
assert qualification.depth == models.TrainingItemQualification.STARTED
|
||||
|
||||
@@ -29,7 +29,7 @@ def test_add_qualification_reversion(admin_client, trainee, training_item, super
|
||||
assert response.status_code == 302
|
||||
qual = models.TrainingItemQualification.objects.last()
|
||||
assert qual is not None
|
||||
assert training_item.pk == qual.item.pk
|
||||
assert training_item.pk == qual.item_id
|
||||
# Ensure only one revision has been created
|
||||
assert Revision.objects.count() == 1
|
||||
response = admin_client.post(url, {'date': date, 'supervisor': supervisor.pk, 'trainee': trainee.pk, 'item': training_item.pk, 'depth': 1})
|
||||
|
||||
@@ -265,5 +265,5 @@ class ItemQualifications(generic.ListView):
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["page_title"] = f"People Qualified In {self.object_list[0].item}"
|
||||
context["page_title"] = f"People Qualified In {models.TrainingItem.objects.get(pk=self.kwargs['pk'])}"
|
||||
return context
|
||||
|
||||
@@ -30,15 +30,15 @@ for app in [apps.get_app_config(label) for label in ("RIGS", "assets", "training
|
||||
modelname = model.__name__.lower()
|
||||
if appname == 'rigboard':
|
||||
urlpatterns += [
|
||||
path('{}/<str:pk>/history/'.format(modelname),
|
||||
permission_required_with_403('{}.change_{}'.format(app.label, modelname))(
|
||||
path(f'{modelname}/<str:pk>/history/',
|
||||
permission_required_with_403(f'{app.label}.change_{modelname}')(
|
||||
views.VersionHistory.as_view()),
|
||||
name='{}_history'.format(modelname), kwargs={'model': model, 'app': appname, }),
|
||||
name=f'{modelname}_history', kwargs={'model': model, 'app': appname, }),
|
||||
]
|
||||
else:
|
||||
urlpatterns += [
|
||||
path('{}/{}/<str:pk>/history/'.format(appname, modelname),
|
||||
permission_required_with_403('{}.change_{}'.format(app.label, modelname))(
|
||||
path(f'{appname}/{modelname}/<str:pk>/history/',
|
||||
permission_required_with_403(f'{app.label}.change_{modelname}')(
|
||||
views.VersionHistory.as_view()),
|
||||
name='{}_history'.format(modelname), kwargs={'model': model, 'app': appname, }),
|
||||
name=f'{modelname}_history', kwargs={'model': model, 'app': appname, }),
|
||||
]
|
||||
|
||||
@@ -160,7 +160,10 @@ class ModelComparison:
|
||||
# Build some dicts of what we have
|
||||
item_dict = {} # build a list of items, key is the item_pk
|
||||
for version in old_item_versions: # put all the old versions in a list
|
||||
compare = ModelComparison(old=version._object_version.object, **comparisonParams)
|
||||
old = version._object_version.object
|
||||
if old is None:
|
||||
pass
|
||||
compare = ModelComparison(old=old, **comparisonParams)
|
||||
item_dict[version.object_id] = compare
|
||||
|
||||
for version in new_item_versions: # go through the new versions
|
||||
|
||||
@@ -27,10 +27,10 @@ class VersionHistory(generic.ListView):
|
||||
return get_object_or_404(self.kwargs['model'], pk=self.kwargs['pk'])
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(VersionHistory, self).get_context_data(**kwargs)
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['object'] = self.get_object()
|
||||
if self.kwargs['app'] != 'rigboard':
|
||||
context['override'] = 'base_{}.html'.format(self.kwargs['app'])
|
||||
context['override'] = f'base_{self.kwargs["app"]}.html'
|
||||
|
||||
return context
|
||||
|
||||
@@ -59,10 +59,10 @@ class ActivityTable(generic.ListView):
|
||||
return RIGSVersion.objects.get_for_multiple_models(filter_models(self.kwargs.get('models'), self.request.user)).order_by("-revision__date_created")
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super(ActivityTable, self).get_context_data(**kwargs)
|
||||
context['page_title'] = "{} Activity Stream".format(title(self.kwargs['app']))
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['page_title'] = f"{title(self.kwargs['app'])} Activity Stream"
|
||||
if self.kwargs['app'] != 'rigboard':
|
||||
context['override'] = 'base_{}.html'.format(self.kwargs['app'])
|
||||
context['override'] = f'base_{self.kwargs["app"]}.html'
|
||||
|
||||
return context
|
||||
|
||||
@@ -77,7 +77,7 @@ class ActivityFeed(generic.ListView): # Appears on homepage
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
# Call the base implementation first to get a context
|
||||
context = super(ActivityFeed, self).get_context_data(**kwargs)
|
||||
context = super().get_context_data(**kwargs)
|
||||
context['page_title'] = "Activity Feed"
|
||||
maxTimeDelta = datetime.timedelta(hours=1)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user