Compare commits

..

33 Commits

Author SHA1 Message Date
12c4b63947 Revert "Does this help the coverage be less weird?"
This reverts commit 39ab9df836.
2021-01-26 23:53:59 +00:00
39ab9df836 Does this help the coverage be less weird? 2021-01-26 23:36:26 +00:00
a99e4b1d1c What about this?
Swear I spend my life jiggerypokerying the damn test suite...
2021-01-26 21:51:59 +00:00
18a091f8ea What about this? 2021-01-26 19:42:54 +00:00
d64d0f54d4 Should fix asset test on CI 2021-01-26 19:37:12 +00:00
8f54897b69 Upload failure screenshots as individual artifacts not a zip
Turns out I can't unzip things from my phone, which is a pain
2021-01-26 19:31:06 +00:00
97830596b5 Fix unauth test to not just immediately pass out 2021-01-26 19:15:29 +00:00
68f401097d Add title checking to the slightly insane assets test 2021-01-26 17:43:01 +00:00
8c5b2f426d Refactor asset audit tests with better selectors
Also fixed a silly title error with the modal
2021-01-26 15:08:51 +00:00
e3fc05772e Exclude tests from the coverage stats
Seems to be artifically deflating our stats
2021-01-26 13:42:58 +00:00
e38205b9e7 Oops, remove unused import 2021-01-25 22:45:02 +00:00
f2b9642772 Switch to gh-a artifact uploading instead of imgur 'hack'
For test failure screenshots. Happy now @mattysmith22? ;p
2021-01-25 22:27:21 +00:00
08939a0e1f Purge old .idea config 2021-01-25 22:18:15 +00:00
15b7f9c7c1 No Ruby compass bodge, no need for rubocop! 2021-01-25 22:17:37 +00:00
c67f7e1e54 Purge old vagrant config 2021-01-25 22:16:25 +00:00
4f268b3168 Cache python dependencies
Should majorly speedup parallelillelelised testing
2021-01-25 22:08:32 +00:00
0e7723828a Update python version in tests 2021-01-25 21:59:23 +00:00
c46a2c53f3 Run parallelised RIGS tests as one matrix job 2021-01-25 21:55:32 +00:00
b3617a74bf Define service in coveralls task 2021-01-25 21:44:05 +00:00
5806cbc72d Change python ver 2021-01-25 21:42:55 +00:00
ab2ff9f146 Fix whoops in requirements.txt 2021-01-25 21:39:44 +00:00
fd5575a818 You valid now? 2021-01-25 21:37:22 +00:00
402a1dd7f0 Tends to help if I push valid yaml 2021-01-25 21:29:32 +00:00
be7688aa75 Upgrade python deps 2021-01-25 18:14:49 +00:00
a472e414f7 Add basic calendar button test
Mainly to pickup on FullCalendar loading errors
2021-01-25 18:09:21 +00:00
618c02aa9c Attempt at parallelising tests where possible 2021-01-25 16:42:12 +00:00
3056b6ef71 Fix audit time check in asset audit test 2021-01-25 16:07:44 +00:00
548c960996 npm upgrade 2021-01-25 15:50:36 +00:00
2cc43dcdb7 Move some gulp deps to dev rather than prod 2021-01-25 15:39:51 +00:00
6db25fb56b Upgrade to heroku-20 stack 2021-01-25 15:39:04 +00:00
8ad629a47e Replace Travis with Github Actions (#416)
Closes #415

Also enables coverage tracking of Django templates, hence the ~30% drop in coverage!
2021-01-25 01:20:12 +00:00
dependabot[bot]
2414eb9724 Build(deps): Bump lxml from 4.5.0 to 4.6.2 (#417)
Bumps [lxml](https://github.com/lxml/lxml) from 4.5.0 to 4.6.2.
- [Release notes](https://github.com/lxml/lxml/releases)
- [Changelog](https://github.com/lxml/lxml/blob/master/CHANGES.txt)
- [Commits](https://github.com/lxml/lxml/compare/lxml-4.5.0...lxml-4.6.2)

Signed-off-by: dependabot[bot] <support@github.com>

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2021-01-24 00:23:54 +00:00
3414204209 Refactor buildsystem to NPM/Gulp, port to BS4 & rewrite RIGS tests accordingly... (#412)
* Start to seperate versioning into its own app

* Start reworking invoice things

* Reduced overall font size a touch

* Improvements to generic lists

* Tweak some colours to be a bit less OTT

I need to work out if I can seperate background and primary colours like BS3 did

* Improvements to event table mobile

* First pass at mobile-ising the generic list

* Item table fixes

* Fixed fullcalendar print css not included

* Asset list table improvements

* Tweak asset list to be more in line with other lists

* Versioning template improvements

//TODO Rather than have seperate asset templates, convert 'id' into a template variable

* Tweak versioning templates to allow ID overrides

Asset specific templates begone. Still need to bring back the ID formatting for the Rigboard.

* Asset form fixes

* Use the right autocompleter.js...

* Breakout (most) user stuff to separate module

The model remains in RIGS for now, as it's pretty painful to move...

* Python Format/import opt

* Test Refactor Part 1 - Shuffle things around

* Fix migrations

TODO - need to ensure moved models are *moved* rather than deleted and recreated!

* Start on new tests

* Initial work on event create test reimpl

* Init other tests, more rigs test faffery

* Desaturate theme colors even more

Much closer to BS3

* Fix event item adding

Bit too heavy handed with the deduplication there Arona

* Initial refactor of event item testing

* Upgrade bootstrap-select

* Updated bootstrap-select for BS4

* Initial port of duplicate testing

Needs the latter half rewriting once we have an EventDetail POM

* Refactor date validation test

So close to killing test_functional.EventTest!

* Deduplication of testing code

* pep8

* Fix some tests

And some things that were actually borked

* FIX: Prevent setting access time after start time 

Cherry pick of d274ea4606. Will close #405.

* Refactor calendar tests

* FIX: Don't show asset buttons/history for basic users

* Really ought to get a pre-commit hook for pep8...

* Fully replace test_functional

* Dedupe generic search logic

* Fix the remaining tests

* Ensure submit button is scrolled to in tests

* Fix asset creation test + actually verify its results

* Make CI use latest (stable) chromedriver rather than some ancient one

Since Travis uses the latest stable chrome, should always match. Bash oneliner \o/

* Of course | is part of YAML syntax, of course...

Maybe this works.

* Update python version

Trying to get CI to match my local environment as much as possible...

* Minor test futzing

* Well that wasn't clever of me

* That was even less clever of me

* Revert to old submit wait behaviour

* What about if I did this

* Try disabling chrome cache

* Added screenshot recording of test failures

* Fixed RIGS tests not being run

* Fixed Pep8 - I promise I'll make a pre-commit hook sometime!

* Very initial work at togglable darktheme.

Dammit @alexdaniel654 just when I had my scope creep kinda under control. It'll be v. nice to have though...!

* More dark theme wangling

* Fix some asset template things

* FIX: CI Locale Issues

* Fix sample command

* Initial work at integrating the risk assessment

#136. No clever database structure as yet...

* FIX: Don't set every boolean input to radios

* Different approach to RA linking

* Move text definitions to somewhere more authoratitive

* FIX: Undo breakage causing autopep8

o.O

* Expand detail template

* Use correct view for RA history

* Initial work at coercing activity feed into showing RAs

Also shows Asset/Supplier on the homepage feed.

* Refactor activity feed template logic

Yay for removing arbitrary if/else chains!

* Initial work on caching activity feed

Server side that is. Ref #162.

* Start RA list template

* Refactor RA creation stuff, again

* Add H&S Details to Event Detail View

* Display venue notes in event detail

Notes are no use if nobody reads them. Not sure on this one.

* Add ability to filter event archive by status

Closes #168.

* Fix lingering naive time

* Use locmem cache in sqlite environments

Otherwise the tests just lock up totally. Should close #162

* Update dependencies

Mirrors/supersedes 0e67da82e2

* Add global ctrl/meta-enter shortcut for form submission

Wants rewriting for better efficiency, but hey, it works!

* Update dependencies

* Fix for a situation that should be impossible

* Fix navbar alignment

* FEAT: Improve 'omni'search

- Partialised template
- Added to assets header
- Added ability to search assets/suppliers
- Improved selection logic
- Have it display current query

* Move closemodal into PyRIGS

* Fix tests for search improvements

* Dark mode colour improvements

* Fix table colors for dry hires

* further darktheme fixes

* Remove the dark header from light theme

* Fix reload loops when CSS/JS is changed

* Move dark theme SCSS to separate file, fix inactive pagination styling

* Genercise detail pages

* Testing something re notes

I wonder if I can make that global, rather than per-template...

* Dark theme palette shenanigans

I just can't decide

* Match darktheme palette to forum darktheme palette

Why reinvent the wheel.

* Make supplier detail use the generic template

* Disable mobile event table PoC for now

* Remove the defaults from the RA fields + make them required

* More RA fixes

* Fixes to revisions for RAs

* Add bootstrap 4 test page

* Bunch of dark mode fixes from test page

* Do not use Django 'required' for radio selects

As this requires them to be True, whereas we just need to require that an option be entered.

* Properly fixed popover darktheme

* Fixed search for events

* Style fixes to asset list

* Start RA 'mark review' feature

* Add reviewing to revision history, fix RA editing not working

Also actually commit all the files, that helps

* Fix Power MIC being lost on RA edit

Why it is subtly different to the Event Update behaviour? Who knows

* Invalidate RA review if it is edited after review

* Start work on event checklist

* Add a button for creating and instantly voiding invoices

Handy dandy for when you have loads of cancelled events, like say, a pandemic

* Mooooore status chips, mooore

* Initial shenanigans on storing my overly fancy EC form

* Proof of concept for JSON parsing/storage

\o/

* Add new line functionality for vehicles/drivers

Might it have been easier to create 'dummy' models like with EventItems? Probably...

* Alter rig_count to not include un-checked-in dry hires

* Insert a divider between still-out dry hires and actually upcoming events on rigboard

* Initial work on new checklist handling. No more JSON!

* Versioning module now does magic

Automatic creation of views/urls for anything registered with reversion, with a small amount of hackage to preserve legacy stuff. (and the DAMNED asset IDs!) I would never get distracted...

* Cleanup

* Event checklist crew works

Mostly - its not happy with timezones

* Medium event power stuff done, barring worst case stuff

* Misc fixes

* Validation of power reqs

* Worst case points on checklist

* Templating improvements to RA/EC stuff

* Do event table color logic at python level

* Audit template fixes

* Restrict versioning to one level of depth for speed

Also fixed the template for nested changes

* Event properties internal/authorised always return a explicit boolean rather than sometimes None

* Use template filter for notes

* Fix list templates

TODO: Sensible place to define the 'expected answer' stuff.

* Fix cable table template

* Rethink rigboard color logic again

Also revert some broken stuff

* Test fixes

* Modify auth test so it doesn't try and test for external authorisations

Cause that's not a thing

* Why does this work

Bloody overzealous autoformatter...

* Formatting...

* Initial work on RA tests

* Pages/start of tests for EventChecklists

* Much better coverage of H&S things

* Cleanup & Squash migrations

* Fix wrong variable name in settings.py

* Fix broken invoice list template

* Add revision history to invoices/payments.

Also patches previously introduced reversion permissions hole.

Supersedes and closes #337.

* Various misc fixes

* Fix for my fix

* Curse youuuuu pep8

* Invoice template improvements

* Minor fixes

* More tweaks

* More fixes

* Major improvements/fixes to authorisation templates

* Add ability to mark event checklists as Large Event

This just disables the checks to allow the rest of it to be filled out for large events, though I expect paper forms may still be used...

* Remove database ID from generic list

* Put power threshold values in a collapse

* Use template filter for consistent removal of 'None links'

Plus cleaner template markup! More HTML-in-Python tho, which always feels a bit CSS-in-JS

* Tweak asset list markup

* Begin to change add buttons success -> primary

Also change search primary -> info to avoid clash

* Begin to improve event checklist on mobile

* Asset detail template improvements

* Fix #326 (again)

* Fix errors being squashed

* Fix rigboard validation tests

* Initial work on BS4 button templatetag

Newfeatureitis strikes again

* Allow multiple event checklists per event

TODO: Status chip now needs rethinking

* Minor event detail fixes

* Fix tests

* Rework button tag

* Mobile fixes for search

* Fix event checklist on mobile

* Redo light theme palette

* Switch rigboard new button to primary

* Kill off excess whitespace on rigboard

* Rigboard Timing display tweaks

* Fix tests

* Properly handle eventauthorisations in new versioning

It's not great, not terrible...

* Prevent creating duplicate revisions on event

Potential fix for #322 - I couldn't reproduce even before this change...

* Template improvements

* Minor test fixes

* Revert "Prevent creating duplicate revisions on event"

Apparently it was too strong at preventing dupes...

This reverts commit cce0ad0f9f.

# Conflicts:
#	RIGS/models.py

* Better approach to generic list templates + other deduplication

* Also apply better approach to generic detail pages

* One of these days I'll remember to test BEFORE pushing...

* And now the same for generic forms

* Display tick/cross rather than true/false in boolean version diffs

* Upgrade dependencies

* Fixes fixes fixes

* Fix dependency hell

Probably

* Correct handling of spaces in paperwork filenames

Also normalises display of Invoice IDs. Partial fix for #391.

* Buggerit millennium hand and shrimp

Knew I was gonna forget to fix the tests

* FIX: Set duplicated event status to provisional

Closes #398.

Flip flop. Flip flop.

* Update polyfill for datetime-local

Bloody Firefox. We love to hate you. Proper CSS of the fill to come, SoonTM.

Closes #391

* Curses!

* Minor typo fixes

* Initial pass at soop-consult confirmation screen for RAs

* Fix migration

* Make venue/date editable on EC

For multi venue, multi day events

Defaults to date and venue set on the event. Also made power MIC default to that set in RA

* Clearer logic for RA inverted fields

* (probably) fix tests

* Give keyholders supplier edit perm

* Generic list only displays edit button if user has perm

* Same perm check for generic details

* H&S Details takes up free space on non-internal events

* Remove flash of content when loading new rig page

* First pass at clearer display of asset list filters

* Fix tests / default to headless tests

(fingers crossed)

* Fix autocompleter.js to properly disable edit links again

* Move status color logic back to template

Cause that somehow makes it work better??

* Display note icon on event detail page

* Fix caching

* Put rounded corners back where they belong

* Remove lingering use of 'page-header'

BS removed that style

* More search and replace for BS changes

Thought I'd got them all. Clearly not!

* Remove enforced linebreak on status chips

* Fix horizontal-ness on some forms

* Remove animation on prefers-reduced-motion/low referesh rate devices

Also normalises handling of asset list cable table & improves its use of space on large devices

* Make version changes badges more readable

* First pass at making the calendar less crap

* Fix event table success logic

Yay for copy paste fails >.>

* Use borders rather than block colors for coloured tables under darktheme

* First pass at porting calendar from FC V3 to V5

Two major versions and all they did was rename a bunch of names...TWICE.

* Rework version name method to avoid blank names on eventchecklist vehicles/crew

* Fix cable test

* Made radio button focus much more obvious on dark theme

* Implement Jerb's wording changes

* Fix one test, break another...

* Fix recent change stream list mutation issue

* FIX: Do not naively cache event table

Not that easy, it turns out. Duh.

* FEAT: Implement #413 show associated assets on cable type detail pg

Closes #413

* Allow H&S for non-events

* Update emergency contact number

* Improvements to profile detail page

* Implement some of Jonny's suggested changes

TODO:
- Define event size at RA time, pass through to EC
- Have later power questions be context dependent

* Test fixes

* Add space for power/rigging plans to be linked to RAs

* Start move of event size logic to RA from Ec

* Javascript required shenanigans for RA power

* More moving of event size logic

* Fixing tests for new logic etc

* Why does this work

Indeed, it may not

* FIX: Stupid typo in versioning.py

* Further minor fixes to versioning

* Add icons to H&S menu items

* Should fix calendar breaking in production

* Small alignment fix in asset list

* Squash migrations

Co-authored-by: Matthew Smith <psyms13@nottingham.ac.uk>
2021-01-23 22:22:37 +00:00
53 changed files with 6312 additions and 6181 deletions

View File

@@ -1,6 +1,9 @@
[run]
source =
./
plugins =
django_coverage_plugin
omit =
*/migrations/*
*/tests/*

83
.github/workflows/django.yml vendored Normal file
View File

@@ -0,0 +1,83 @@
name: Django CI
on:
push:
branches: [master]
pull_request:
branches: [master]
jobs:
build:
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
runs-on: ubuntu-latest
if: "!contains(github.event.head_commit.message, '[ci skip]')"
strategy:
matrix:
test-group: ["RIGS.tests.test_unit RIGS.tests.test_models RIGS.tests.test_functional", "versioning.tests.test_versioning", "users.tests.test_users"]
parallel: [true]
include:
- test-group: "assets.tests.test_assets"
parallel: false
- test-group: "RIGS.tests.test_interaction"
parallel: false
steps:
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: 3.9
- name: Cache python deps
uses: actions/cache@v2
with:
path: ${{ env.pythonLocation }}
key: ${{ env.pythonLocation }}-${{ hashFiles('requirements.txt') }}
- name: Setup Chromedriver
if: \!${{ matrix.parallel }}
run: |
wget https://chromedriver.storage.googleapis.com/2.36/chromedriver_linux64.zip
unzip chromedriver_linux64.zip
export PATH=$PATH:$(pwd)
chmod +x chromedriver
export PATH=$PATH:/usr/lib/chromium-browser/
- name: Install Dependencies
run: |
python -m pip install --upgrade pip
pip install pycodestyle coverage coveralls django_coverage_plugin
pip install --upgrade --upgrade-strategy eager -r requirements.txt
python manage.py collectstatic --noinput
- name: Basic Checks
run: |
pycodestyle . --exclude=migrations,importer*
python manage.py check
python manage.py makemigrations --check --dry-run
- name: Run Tests
if: \!${{ matrix.parallel }}
run: coverage run manage.py test ${{ matrix.test-group }} --verbosity=2
- uses: actions/upload-artifact@v2
if: failure() # Screenshots only make sense for the non-parallel, i.e. interaction tests anyway
with:
name: failure-screenshots ${{ matrix.test-group }}
path: screenshots/
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
run: coveralls --service=github
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
COVERALLS_FLAG_NAME: ${{ matrix.test-group }}
COVERALLS_PARALLEL: true
coveralls:
name: Indicate completion to coveralls.io
needs: build
runs-on: ubuntu-latest
container: python:3-slim
steps:
- name: Finished
run: |
pip3 install --upgrade coveralls
coveralls --service=github --finish
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

1
.idea/.name generated
View File

@@ -1 +0,0 @@
PyRIGS

5
.idea/encodings.xml generated
View File

@@ -1,5 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
</project>

8
.idea/modules.xml generated
View File

@@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/pyrigs.iml" filepath="$PROJECT_DIR$/.idea/pyrigs.iml" />
</modules>
</component>
</project>

View File

@@ -1,5 +0,0 @@
<component name="DependencyValidationManager">
<state>
<option name="SKIP_IMPORT_STATEMENTS" value="false" />
</state>
</component>

7
.idea/vcs.xml generated
View File

@@ -1,7 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
</component>
</project>

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,3 @@
*.sqlite3
*.scss
*.md
*.rb
Vagrantfile
config/vagrant/*
config/vagrant.yml

View File

@@ -1,37 +0,0 @@
language: python
python:
"3.8"
cache: pip
addons:
chrome: stable
before_install:
- export LANGUAGE=en_GB.UTF-8
install:
- |
latest=$(wget -qO- https://chromedriver.storage.googleapis.com/LATEST_RELEASE)
wget https://chromedriver.storage.googleapis.com/$latest/chromedriver_linux64.zip
- unzip chromedriver_linux64.zip
- export PATH=$PATH:$(pwd)
- chmod +x chromedriver
- pip install -r requirements.txt
- pip install coveralls codeclimate-test-reporter pycodestyle
before_script:
- export PATH=$PATH:/usr/lib/chromium-browser/
- python manage.py collectstatic --noinput
script:
- pycodestyle . --exclude=migrations,importer*
- python manage.py check
- python manage.py makemigrations --check --dry-run
- coverage run manage.py test --verbosity=2
after_success:
- coveralls
- codeclimate-test-reporter
notifications:
webhooks: https://fathomless-fjord-24024.herokuapp.com/notify

View File

@@ -13,6 +13,7 @@ import os
import raven
import secrets
import datetime
from envparse import env
BASE_DIR = os.path.dirname(os.path.dirname(__file__))
@@ -20,15 +21,15 @@ BASE_DIR = os.path.dirname(os.path.dirname(__file__))
# See https://docs.djangoproject.com/en/1.7/howto/deployment/checklist/
# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = os.environ.get('SECRET_KEY') if os.environ.get(
'SECRET_KEY') else 'gxhy(a#5mhp289_=6xx$7jh=eh$ymxg^ymc+di*0c*geiu3p_e'
SECRET_KEY = env('SECRET_KEY', default='gxhy(a#5mhp289_=6xx$7jh=eh$ymxg^ymc+di*0c*geiu3p_e')
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = bool(int(os.environ.get('DEBUG'))) if os.environ.get('DEBUG') else True
DEBUG = env('DEBUG', cast=bool, default=True)
STAGING = bool(int(os.environ.get('STAGING'))) if os.environ.get('STAGING') else False
STAGING = env('STAGING', cast=bool, default=False)
CI = bool(int(os.environ.get('CI'))) if os.environ.get('CI') else False
CI = env('CI', cast=bool, default=False)
ALLOWED_HOSTS = ['pyrigs.nottinghamtec.co.uk', 'rigs.nottinghamtec.co.uk', 'pyrigs.herokuapp.com']
@@ -174,10 +175,7 @@ else:
}
RAVEN_CONFIG = {
'dsn': os.environ.get('RAVEN_DSN'),
# If you are using git, you can also automatically configure the
# release based on the git info.
# 'release': raven.fetch_git_sha(os.path.dirname(os.path.dirname(__file__))),
'dsn': env('RAVEN_DSN', default=""),
}
# User system
@@ -190,10 +188,8 @@ LOGOUT_URL = '/user/logout/'
ACCOUNT_ACTIVATION_DAYS = 7
# reCAPTCHA settings
RECAPTCHA_PUBLIC_KEY = os.environ.get('RECAPTCHA_PUBLIC_KEY',
"6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI") # If not set, use development key
RECAPTCHA_PRIVATE_KEY = os.environ.get('RECAPTCHA_PRIVATE_KEY',
"6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe") # If not set, use development key
RECAPTCHA_PUBLIC_KEY = env('RECAPTCHA_PUBLIC_KEY', default="6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI") # If not set, use development key
RECAPTCHA_PRIVATE_KEY = env('RECAPTCHA_PUBLIC_KEY', default="6LeIxAcTAAAAAGG-vFI1TnRWxMZNFuojJ4WifJWe") # If not set, use development key
NOCAPTCHA = True
SILENCED_SYSTEM_CHECKS = ['captcha.recaptcha_test_key_error']
@@ -202,13 +198,13 @@ SILENCED_SYSTEM_CHECKS = ['captcha.recaptcha_test_key_error']
EMAILER_TEST = False
if not DEBUG or EMAILER_TEST:
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
EMAIL_HOST = os.environ.get('EMAIL_HOST')
EMAIL_PORT = int(os.environ.get('EMAIL_PORT', 25))
EMAIL_HOST_USER = os.environ.get('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = os.environ.get('EMAIL_HOST_PASSWORD')
EMAIL_USE_TLS = bool(int(os.environ.get('EMAIL_USE_TLS', 0)))
EMAIL_USE_SSL = bool(int(os.environ.get('EMAIL_USE_SSL', 0)))
DEFAULT_FROM_EMAIL = os.environ.get('EMAIL_FROM')
EMAIL_HOST = env('EMAIL_HOST')
EMAIL_PORT = env('EMAIL_PORT', cast=int, default=25)
EMAIL_HOST_USER = env('EMAIL_HOST_USER')
EMAIL_HOST_PASSWORD = env('EMAIL_HOST_PASSWORD')
EMAIL_USE_TLS = env('EMAIL_USE_TLS', cast=bool, default=False)
EMAIL_USE_SSL = env('EMAIL_USE_SSL', cast=bool, default=False)
DEFAULT_FROM_EMAIL = env('EMAIL_FROM')
else:
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
@@ -267,10 +263,3 @@ USE_GRAVATAR = True
TERMS_OF_HIRE_URL = "http://www.nottinghamtec.co.uk/terms.pdf"
AUTHORISATION_NOTIFICATION_ADDRESS = 'productions@nottinghamtec.co.uk'
RISK_ASSESSMENT_URL = os.environ.get('RISK_ASSESSMENT_URL') if os.environ.get(
'RISK_ASSESSMENT_URL') else "http://example.com"
RISK_ASSESSMENT_SECRET = os.environ.get('RISK_ASSESSMENT_SECRET') if os.environ.get(
'RISK_ASSESSMENT_SECRET') else secrets.token_hex(15)
IMGUR_UPLOAD_CLIENT_ID = os.environ.get('IMGUR_UPLOAD_CLIENT_ID', '')
IMGUR_UPLOAD_CLIENT_SECRET = os.environ.get('IMGUR_UPLOAD_CLIENT_SECRET', '')

View File

@@ -6,7 +6,6 @@ import os
import pytz
from datetime import date, time, datetime, timedelta
from django.conf import settings
import imgurpython
import PyRIGS.settings
import sys
import pathlib
@@ -21,13 +20,8 @@ def create_datetime(year, month, day, hour, min):
def create_browser():
options = webdriver.ChromeOptions()
options.add_argument("--window-size=1920,1080")
# No caching, please and thank you
options.add_argument("--aggressive-cache-discard")
options.add_argument("--disk-cache-size=0")
# God Save The Queen
options.add_argument("--lang=en_GB")
options.add_argument("--headless")
if os.environ.get('CI', False):
if settings.CI:
options.add_argument("--no-sandbox")
driver = webdriver.Chrome(options=options)
return driver
@@ -64,19 +58,7 @@ def screenshot_failure(func):
if not pathlib.Path("screenshots").is_dir():
os.mkdir("screenshots")
self.driver.save_screenshot(screenshot_file)
if settings.IMGUR_UPLOAD_CLIENT_ID != "":
config = {
'album': None,
'name': screenshot_name,
'title': screenshot_name,
'description': ""
}
client = imgurpython.ImgurClient(settings.IMGUR_UPLOAD_CLIENT_ID, settings.IMGUR_UPLOAD_CLIENT_SECRET)
image = client.upload_from_path(screenshot_file, config=config)
print("Error in test {} is at url {}".format(screenshot_name, image['link']), file=sys.stderr)
else:
print("Error in test {} is at path {}".format(screenshot_name, screenshot_file), file=sys.stderr)
print("Error in test {} is at path {}".format(screenshot_name, screenshot_file), file=sys.stderr)
raise e
return wrapper_func

View File

@@ -1,5 +1,6 @@
from pypom import Region
from django.utils import timezone
from django.conf import settings
from selenium.webdriver.common.by import By
from selenium.webdriver.support import expected_conditions
from selenium.webdriver.remote.webelement import WebElement
@@ -19,18 +20,22 @@ def parse_bool_from_string(string):
else:
return False
# 12-Hour vs 24-Hour Time. Affects widget display
def get_time_format():
# Default
time_format = "%H:%M"
# If system is 12hr
if timezone.now().strftime("%p"):
time_format = "%I:%M %p"
time_format = "%H%M"
if settings.CI: # The CI is American
time_format = "%I%M%p"
return time_format
def get_date_format():
date_format = "%d%m%Y"
if settings.CI: # And try as I might I can't stop it being so
date_format = "%m%d%Y"
return date_format
class BootstrapSelectElement(Region):
_main_button_locator = (By.CSS_SELECTOR, 'button.dropdown-toggle')
_option_box_locator = (By.CSS_SELECTOR, 'ul.dropdown-menu')
@@ -150,13 +155,13 @@ class DatePicker(Region):
def set_value(self, value):
self.root.clear()
self.root.send_keys(value.strftime("%d%m%Y"))
self.root.send_keys(value.strftime(get_date_format()))
class TimePicker(Region):
@property
def value(self):
return datetime.datetime.strptime(self.root.get_attribute("value"), get_time_format())
return datetime.datetime.strptime(self.root.get_attribute("value"), "%H:%M")
def set_value(self, value):
self.root.clear()
@@ -166,12 +171,12 @@ class TimePicker(Region):
class DateTimePicker(Region):
@property
def value(self):
return datetime.datetime.strptime(self.root.get_attribute("value"), "%Y-%m-%d " + get_time_format())
return datetime.datetime.strptime(self.root.get_attribute("value"), "%Y-%m-%d %H:%M")
def set_value(self, value):
self.root.clear()
date = value.date().strftime("%d%m%Y")
date = value.date().strftime(get_date_format())
time = value.time().strftime(get_time_format())
self.root.send_keys(date)

View File

@@ -1,5 +1,5 @@
# TEC PA & Lighting - PyRIGS #
[![Build Status](https://travis-ci.org/nottinghamtec/PyRIGS.svg?branch=master)](https://travis-ci.org/nottinghamtec/PyRIGS)
![Build Status](https://github.com/nottinghamtec/PyRIGS/workflows/Django%20CI/badge.svg)
[![Coverage Status](https://coveralls.io/repos/github/nottinghamtec/PyRIGS/badge.svg)](https://coveralls.io/github/nottinghamtec/PyRIGS)
Welcome to TEC PA & Lighting's PyRIGS program. This is a reimplementation of the previous Rig Information Gathering System (RIGS) that was developed using Ruby on Rails. PyRIGS is our in house app for the centralisation of information on our events and now assets.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
/*!
* Bootstrap alert.js v4.5.2 (https://getbootstrap.com/)
* Copyright 2011-2020 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Bootstrap alert.js v4.6.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("jquery"),require("./util.js")):"function"==typeof define&&define.amd?define(["jquery","./util.js"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).Alert=t(e.jQuery,e.Util)}(this,(function(e,t){"use strict";function n(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}e=e&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e,t=t&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t;var r=e.fn.alert,o=function(){function r(e){this._element=e}var o,l,i,a=r.prototype;return a.close=function(e){var t=this._element;e&&(t=this._getRootElement(e)),this._triggerCloseEvent(t).isDefaultPrevented()||this._removeElement(t)},a.dispose=function(){e.removeData(this._element,"bs.alert"),this._element=null},a._getRootElement=function(n){var r=t.getSelectorFromElement(n),o=!1;return r&&(o=document.querySelector(r)),o||(o=e(n).closest(".alert")[0]),o},a._triggerCloseEvent=function(t){var n=e.Event("close.bs.alert");return e(t).trigger(n),n},a._removeElement=function(n){var r=this;if(e(n).removeClass("show"),e(n).hasClass("fade")){var o=t.getTransitionDurationFromElement(n);e(n).one(t.TRANSITION_END,(function(e){return r._destroyElement(n,e)})).emulateTransitionEnd(o)}else this._destroyElement(n)},a._destroyElement=function(t){e(t).detach().trigger("closed.bs.alert").remove()},r._jQueryInterface=function(t){return this.each((function(){var n=e(this),o=n.data("bs.alert");o||(o=new r(this),n.data("bs.alert",o)),"close"===t&&o[t](this)}))},r._handleDismiss=function(e){return function(t){t&&t.preventDefault(),e.close(this)}},o=r,i=[{key:"VERSION",get:function(){return"4.5.2"}}],(l=null)&&n(o.prototype,l),i&&n(o,i),r}();return e(document).on("click.bs.alert.data-api",'[data-dismiss="alert"]',o._handleDismiss(new o)),e.fn.alert=o._jQueryInterface,e.fn.alert.Constructor=o,e.fn.alert.noConflict=function(){return e.fn.alert=r,o._jQueryInterface},o}));
!function(e,t){"object"==typeof exports&&"undefined"!=typeof module?module.exports=t(require("jquery"),require("./util.js")):"function"==typeof define&&define.amd?define(["jquery","./util"],t):(e="undefined"!=typeof globalThis?globalThis:e||self).Alert=t(e.jQuery,e.Util)}(this,(function(e,t){"use strict";function n(e){return e&&"object"==typeof e&&"default"in e?e:{default:e}}var r=n(e),l=n(t);function u(e,t){for(var n=0;n<t.length;n++){var r=t[n];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}var a="bs.alert",o=r.default.fn.alert,i=function(){function e(e){this._element=e}var t,n,o,i=e.prototype;return i.close=function(e){var t=this._element;e&&(t=this._getRootElement(e)),this._triggerCloseEvent(t).isDefaultPrevented()||this._removeElement(t)},i.dispose=function(){r.default.removeData(this._element,a),this._element=null},i._getRootElement=function(e){var t=l.default.getSelectorFromElement(e),n=!1;return t&&(n=document.querySelector(t)),n||(n=r.default(e).closest(".alert")[0]),n},i._triggerCloseEvent=function(e){var t=r.default.Event("close.bs.alert");return r.default(e).trigger(t),t},i._removeElement=function(e){var t=this;if(r.default(e).removeClass("show"),r.default(e).hasClass("fade")){var n=l.default.getTransitionDurationFromElement(e);r.default(e).one(l.default.TRANSITION_END,(function(n){return t._destroyElement(e,n)})).emulateTransitionEnd(n)}else this._destroyElement(e)},i._destroyElement=function(e){r.default(e).detach().trigger("closed.bs.alert").remove()},e._jQueryInterface=function(t){return this.each((function(){var n=r.default(this),l=n.data(a);l||(l=new e(this),n.data(a,l)),"close"===t&&l[t](this)}))},e._handleDismiss=function(e){return function(t){t&&t.preventDefault(),e.close(this)}},t=e,o=[{key:"VERSION",get:function(){return"4.6.0"}}],(n=null)&&u(t.prototype,n),o&&u(t,o),e}();return r.default(document).on("click.bs.alert.data-api",'[data-dismiss="alert"]',i._handleDismiss(new i)),r.default.fn.alert=i._jQueryInterface,r.default.fn.alert.Constructor=i,r.default.fn.alert.noConflict=function(){return r.default.fn.alert=o,i._jQueryInterface},i}));

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
/*!
* Bootstrap popover.js v4.5.2 (https://getbootstrap.com/)
* Copyright 2011-2020 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Bootstrap popover.js v4.6.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("jquery"),require("./tooltip.js")):"function"==typeof define&&define.amd?define(["jquery","./tooltip.js"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).Popover=e(t.jQuery,t.Tooltip)}(this,(function(t,e){"use strict";function n(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}function o(){return(o=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(t[o]=n[o])}return t}).apply(this,arguments)}t=t&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t,e=e&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e;var r="popover",i=".bs.popover",s=t.fn[r],p=new RegExp("(^|\\s)bs-popover\\S+","g"),u=o({},e.Default,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>'}),a=o({},e.DefaultType,{content:"(string|element|function)"}),l={HIDE:"hide"+i,HIDDEN:"hidden"+i,SHOW:"show"+i,SHOWN:"shown"+i,INSERTED:"inserted"+i,CLICK:"click"+i,FOCUSIN:"focusin"+i,FOCUSOUT:"focusout"+i,MOUSEENTER:"mouseenter"+i,MOUSELEAVE:"mouseleave"+i},c=function(e){var o,s;function c(){return e.apply(this,arguments)||this}s=e,(o=c).prototype=Object.create(s.prototype),o.prototype.constructor=o,o.__proto__=s;var f,h,d,y=c.prototype;return y.isWithContent=function(){return this.getTitle()||this._getContent()},y.addAttachmentClass=function(e){t(this.getTipElement()).addClass("bs-popover-"+e)},y.getTipElement=function(){return this.tip=this.tip||t(this.config.template)[0],this.tip},y.setContent=function(){var e=t(this.getTipElement());this.setElementContent(e.find(".popover-header"),this.getTitle());var n=this._getContent();"function"==typeof n&&(n=n.call(this.element)),this.setElementContent(e.find(".popover-body"),n),e.removeClass("fade show")},y._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},y._cleanTipClass=function(){var e=t(this.getTipElement()),n=e.attr("class").match(p);null!==n&&n.length>0&&e.removeClass(n.join(""))},c._jQueryInterface=function(e){return this.each((function(){var n=t(this).data("bs.popover"),o="object"==typeof e?e:null;if((n||!/dispose|hide/.test(e))&&(n||(n=new c(this,o),t(this).data("bs.popover",n)),"string"==typeof e)){if(void 0===n[e])throw new TypeError('No method named "'+e+'"');n[e]()}}))},f=c,d=[{key:"VERSION",get:function(){return"4.5.2"}},{key:"Default",get:function(){return u}},{key:"NAME",get:function(){return r}},{key:"DATA_KEY",get:function(){return"bs.popover"}},{key:"Event",get:function(){return l}},{key:"EVENT_KEY",get:function(){return i}},{key:"DefaultType",get:function(){return a}}],(h=null)&&n(f.prototype,h),d&&n(f,d),c}(e);return t.fn[r]=c._jQueryInterface,t.fn[r].Constructor=c,t.fn[r].noConflict=function(){return t.fn[r]=s,c._jQueryInterface},c}));
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("jquery"),require("./tooltip.js")):"function"==typeof define&&define.amd?define(["jquery","./tooltip"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).Popover=e(t.jQuery,t.Tooltip)}(this,(function(t,e){"use strict";function n(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var o=n(t),r=n(e);function i(t,e){for(var n=0;n<e.length;n++){var o=e[n];o.enumerable=o.enumerable||!1,o.configurable=!0,"value"in o&&(o.writable=!0),Object.defineProperty(t,o.key,o)}}function u(){return(u=Object.assign||function(t){for(var e=1;e<arguments.length;e++){var n=arguments[e];for(var o in n)Object.prototype.hasOwnProperty.call(n,o)&&(t[o]=n[o])}return t}).apply(this,arguments)}var f="popover",a="bs.popover",l="."+a,s=o.default.fn[f],c=new RegExp("(^|\\s)bs-popover\\S+","g"),p=u({},r.default.Default,{placement:"right",trigger:"click",content:"",template:'<div class="popover" role="tooltip"><div class="arrow"></div><h3 class="popover-header"></h3><div class="popover-body"></div></div>'}),d=u({},r.default.DefaultType,{content:"(string|element|function)"}),h={HIDE:"hide"+l,HIDDEN:"hidden"+l,SHOW:"show"+l,SHOWN:"shown"+l,INSERTED:"inserted"+l,CLICK:"click"+l,FOCUSIN:"focusin"+l,FOCUSOUT:"focusout"+l,MOUSEENTER:"mouseenter"+l,MOUSELEAVE:"mouseleave"+l},y=function(t){var e,n;function r(){return t.apply(this,arguments)||this}n=t,(e=r).prototype=Object.create(n.prototype),e.prototype.constructor=e,e.__proto__=n;var u,s,y,v=r.prototype;return v.isWithContent=function(){return this.getTitle()||this._getContent()},v.addAttachmentClass=function(t){o.default(this.getTipElement()).addClass("bs-popover-"+t)},v.getTipElement=function(){return this.tip=this.tip||o.default(this.config.template)[0],this.tip},v.setContent=function(){var t=o.default(this.getTipElement());this.setElementContent(t.find(".popover-header"),this.getTitle());var e=this._getContent();"function"==typeof e&&(e=e.call(this.element)),this.setElementContent(t.find(".popover-body"),e),t.removeClass("fade show")},v._getContent=function(){return this.element.getAttribute("data-content")||this.config.content},v._cleanTipClass=function(){var t=o.default(this.getTipElement()),e=t.attr("class").match(c);null!==e&&e.length>0&&t.removeClass(e.join(""))},r._jQueryInterface=function(t){return this.each((function(){var e=o.default(this).data(a),n="object"==typeof t?t:null;if((e||!/dispose|hide/.test(t))&&(e||(e=new r(this,n),o.default(this).data(a,e)),"string"==typeof t)){if(void 0===e[t])throw new TypeError('No method named "'+t+'"');e[t]()}}))},u=r,y=[{key:"VERSION",get:function(){return"4.6.0"}},{key:"Default",get:function(){return p}},{key:"NAME",get:function(){return f}},{key:"DATA_KEY",get:function(){return a}},{key:"Event",get:function(){return h}},{key:"EVENT_KEY",get:function(){return l}},{key:"DefaultType",get:function(){return d}}],(s=null)&&i(u.prototype,s),y&&i(u,y),r}(r.default);return o.default.fn[f]=y._jQueryInterface,o.default.fn[f].Constructor=y,o.default.fn[f].noConflict=function(){return o.default.fn[f]=s,y._jQueryInterface},y}));

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +1,6 @@
/*!
* Bootstrap util.js v4.5.2 (https://getbootstrap.com/)
* Copyright 2011-2020 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Bootstrap util.js v4.6.0 (https://getbootstrap.com/)
* Copyright 2011-2021 The Bootstrap Authors (https://github.com/twbs/bootstrap/graphs/contributors)
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/main/LICENSE)
*/
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).Util=e(t.jQuery)}(this,(function(t){"use strict";t=t&&Object.prototype.hasOwnProperty.call(t,"default")?t.default:t;function e(e){var r=this,o=!1;return t(this).one(n.TRANSITION_END,(function(){o=!0})),setTimeout((function(){o||n.triggerTransitionEnd(r)}),e),this}var n={TRANSITION_END:"bsTransitionEnd",getUID:function(t){do{t+=~~(1e6*Math.random())}while(document.getElementById(t));return t},getSelectorFromElement:function(t){var e=t.getAttribute("data-target");if(!e||"#"===e){var n=t.getAttribute("href");e=n&&"#"!==n?n.trim():""}try{return document.querySelector(e)?e:null}catch(t){return null}},getTransitionDurationFromElement:function(e){if(!e)return 0;var n=t(e).css("transition-duration"),r=t(e).css("transition-delay"),o=parseFloat(n),i=parseFloat(r);return o||i?(n=n.split(",")[0],r=r.split(",")[0],1e3*(parseFloat(n)+parseFloat(r))):0},reflow:function(t){return t.offsetHeight},triggerTransitionEnd:function(e){t(e).trigger("transitionend")},supportsTransitionEnd:function(){return Boolean("transitionend")},isElement:function(t){return(t[0]||t).nodeType},typeCheckConfig:function(t,e,r){for(var o in r)if(Object.prototype.hasOwnProperty.call(r,o)){var i=r[o],a=e[o],u=a&&n.isElement(a)?"element":null==(s=a)?""+s:{}.toString.call(s).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(i).test(u))throw new Error(t.toUpperCase()+': Option "'+o+'" provided type "'+u+'" but expected type "'+i+'".')}var s},findShadowRoot:function(t){if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){var e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?n.findShadowRoot(t.parentNode):null},jQueryDetection:function(){if(void 0===t)throw new TypeError("Bootstrap's JavaScript requires jQuery. jQuery must be included before Bootstrap's JavaScript.");var e=t.fn.jquery.split(" ")[0].split(".");if(e[0]<2&&e[1]<9||1===e[0]&&9===e[1]&&e[2]<1||e[0]>=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}};return n.jQueryDetection(),t.fn.emulateTransitionEnd=e,t.event.special[n.TRANSITION_END]={bindType:"transitionend",delegateType:"transitionend",handle:function(e){if(t(e.target).is(this))return e.handleObj.handler.apply(this,arguments)}},n}));
!function(t,e){"object"==typeof exports&&"undefined"!=typeof module?module.exports=e(require("jquery")):"function"==typeof define&&define.amd?define(["jquery"],e):(t="undefined"!=typeof globalThis?globalThis:t||self).Util=e(t.jQuery)}(this,(function(t){"use strict";function e(t){return t&&"object"==typeof t&&"default"in t?t:{default:t}}var n=e(t),r="transitionend";function o(t){var e=this,r=!1;return n.default(this).one(i.TRANSITION_END,(function(){r=!0})),setTimeout((function(){r||i.triggerTransitionEnd(e)}),t),this}var i={TRANSITION_END:"bsTransitionEnd",getUID:function(t){do{t+=~~(1e6*Math.random())}while(document.getElementById(t));return t},getSelectorFromElement:function(t){var e=t.getAttribute("data-target");if(!e||"#"===e){var n=t.getAttribute("href");e=n&&"#"!==n?n.trim():""}try{return document.querySelector(e)?e:null}catch(t){return null}},getTransitionDurationFromElement:function(t){if(!t)return 0;var e=n.default(t).css("transition-duration"),r=n.default(t).css("transition-delay"),o=parseFloat(e),i=parseFloat(r);return o||i?(e=e.split(",")[0],r=r.split(",")[0],1e3*(parseFloat(e)+parseFloat(r))):0},reflow:function(t){return t.offsetHeight},triggerTransitionEnd:function(t){n.default(t).trigger(r)},supportsTransitionEnd:function(){return Boolean(r)},isElement:function(t){return(t[0]||t).nodeType},typeCheckConfig:function(t,e,n){for(var r in n)if(Object.prototype.hasOwnProperty.call(n,r)){var o=n[r],a=e[r],u=a&&i.isElement(a)?"element":null==(l=a)?""+l:{}.toString.call(l).match(/\s([a-z]+)/i)[1].toLowerCase();if(!new RegExp(o).test(u))throw new Error(t.toUpperCase()+': Option "'+r+'" provided type "'+u+'" but expected type "'+o+'".')}var l},findShadowRoot:function(t){if(!document.documentElement.attachShadow)return null;if("function"==typeof t.getRootNode){var e=t.getRootNode();return e instanceof ShadowRoot?e:null}return t instanceof ShadowRoot?t:t.parentNode?i.findShadowRoot(t.parentNode):null},jQueryDetection:function(){if(void 0===n.default)throw new TypeError("Bootstrap's JavaScript requires jQuery. jQuery must be included before Bootstrap's JavaScript.");var t=n.default.fn.jquery.split(" ")[0].split(".");if(t[0]<2&&t[1]<9||1===t[0]&&9===t[1]&&t[2]<1||t[0]>=4)throw new Error("Bootstrap's JavaScript requires at least jQuery v1.9.1 but less than v4.0.0")}};return i.jQueryDetection(),n.default.fn.emulateTransitionEnd=o,n.default.event.special[i.TRANSITION_END]={bindType:r,delegateType:r,handle:function(t){if(n.default(t.target).is(this))return t.handleObj.handler.apply(this,arguments)}},i}));

View File

@@ -304,3 +304,43 @@ class UserPage(BasePage):
def generate_key(self):
self.find_element(*self._generation_button_selector).click()
class CalendarPage(BasePage):
URL_TEMPLATE = 'rigboard/calendar'
_go_locator = (By.ID, 'go-to-date-button')
_today_selector = (By.ID, 'today-button')
_prev_selector = (By.ID, 'prev-button')
_next_selector = (By.ID, 'next-button')
_month_selector = (By.ID, 'month-button')
_week_selector = (By.ID, 'week-button')
_day_selector = (By.ID, 'day-button')
def go(self):
return self.find_element(*self._go_locator).click()
@property
def target_date(self):
return regions.DatePicker(self, self.find_element(By.ID, 'go-to-date-input'))
def today(self):
return self.find_element(*self._today_selector).click()
def prev(self):
return self.find_element(*self._prev_selector).click()
def next(self):
return self.find_element(*self._next_selector).click()
def month(self):
return self.find_element(*self._month_selector).click()
def week(self):
return self.find_element(*self._week_selector).click()
def day(self):
return self.find_element(*self._day_selector).click()

View File

@@ -645,7 +645,18 @@ class TestCalendar(BaseRigboardTest):
else:
self.assertNotContains(response, "TE E" + str(test) + " ")
# Wow - that was a lot of tests
def test_calendar_buttons(self): # If FullCalendar fails to load for whatever reason, the buttons don't work
self.page = pages.CalendarPage(self.driver, self.live_server_url).open()
self.assertIn(timezone.now().strftime("%Y-%m"), self.driver.current_url)
target_date = datetime.date(2020, 1, 1)
self.page.target_date.set_value(target_date)
self.page.go()
self.assertIn(self.page.target_date.value.strftime("%Y-%m"), self.driver.current_url)
self.page.next()
target_date += datetime.timedelta(days=32)
self.assertIn(target_date.strftime("%m"), self.driver.current_url)
@screenshot_failure_cls

134
Vagrantfile vendored
View File

@@ -1,134 +0,0 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
require 'yaml'
unless File.exist?('config/vagrant.yml')
raise "There is no config/vagrant.yml file.\nCopy config/vagrant.template.yml, make any changes you need, then try again."
end
settings = YAML.load_file 'config/vagrant.yml'
$script = <<SCRIPT
echo Beginning Vagrant provisioning...
date > /etc/vagrant_provisioned_at
SCRIPT
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
VAGRANTFILE_API_VERSION = '2'
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
# The most common configuration options are documented and commented below.
# For a complete reference, please see the online documentation at
# https://docs.vagrantup.com.
config.vm.provision 'shell', inline: $script
# Every Vagrant development environment requires a box. You can search for
# boxes at https://atlas.hashicorp.com/search.
config.vm.box = 'ubuntu/trusty64'
# Share an additional folder to the guest VM. The first argument is
# the path on the host to the actual folder. The second argument is
# the path on the guest to mount the folder. And the optional third
# argument is a set of non-required options.
config.vm.synced_folder ".", "/vagrant"
# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine. In the example below,
# accessing "localhost:5000" will access port 5000 on the guest machine.
config.vm.network "forwarded_port", guest: 5000, host: 5000
# PostgreSQL Server port forwarding
config.vm.network "forwarded_port", host: 15432, guest: 5432
# You can provision with just one of these scripts by user its name, eg:
# $ vagrant provision --provision-with postgresql
config.vm.provision 'build',
type: 'shell',
path: 'config/vagrant/build_dependency_setup.sh'
config.vm.provision 'git',
type: 'shell',
path: 'config/vagrant/git_setup.sh'
config.vm.provision 'postgresql',
type: 'shell',
path: 'config/vagrant/postgresql_setup.sh',
args: [
settings['db']['name'],
settings['db']['user'],
settings['db']['password'],
]
config.vm.provision 'python',
type: 'shell',
path: 'config/vagrant/python_setup.sh'
config.vm.provision 'virtualenv',
type: 'shell',
path: 'config/vagrant/virtualenv_setup.sh',
args: [
settings['virtualenv']['envname'],
]
# Will install foreman and, if there's a Procfile, start it:
config.vm.provision 'foreman',
type: 'shell',
path: 'config/vagrant/foreman_setup.sh',
run: 'always',
args: [
settings['virtualenv']['envname'],
settings['django']['settings_module'],
settings['foreman']['procfile'],
]
# Disable automatic box update checking. If you disable this, then
# boxes will only be checked for updates when the user runs
# `vagrant box outdated`. This is not recommended.
# config.vm.box_check_update = false
# Create a forwarded port mapping which allows access to a specific port
# within the machine from a port on the host machine. In the example below,
# accessing "localhost:8080" will access port 80 on the guest machine.
# config.vm.network "forwarded_port", guest: 80, host: 8080
# Create a private network, which allows host-only access to the machine
# using a specific IP.
# config.vm.network "private_network", ip: "192.168.33.10"
# Create a public network, which generally matched to bridged network.
# Bridged networks make the machine appear as another physical device on
# your network.
# config.vm.network "public_network"
# Provider-specific configuration so you can fine-tune various
# backing providers for Vagrant. These expose provider-specific options.
# Example for VirtualBox:
#
config.vm.provider "virtualbox" do |vb|
# # Display the VirtualBox GUI when booting the machine
# vb.gui = true
#
# # Customize the amount of memory on the VM:
vb.memory = "1024"
end
#
# View the documentation for the provider you are using for more
# information on available options.
# Define a Vagrant Push strategy for pushing to Atlas. Other push strategies
# such as FTP and Heroku are also available. See the documentation at
# https://docs.vagrantup.com/v2/push/atlas.html for more information.
# config.push.define "atlas" do |push|
# push.app = "YOUR_ATLAS_USERNAME/YOUR_APPLICATION_NAME"
# end
# Enable provisioning with a shell script. Additional provisioners such as
# Puppet, Chef, Ansible, Salt, and Docker are also available. Please see the
# documentation for more information about their specific syntax and use.
# config.vm.provision "shell", inline: <<-SHELL
# sudo apt-get update
# sudo apt-get install -y apache2
# SHELL
end

View File

@@ -4,7 +4,7 @@
"scripts": {
"postdeploy": "python manage.py migrate && python manage.py generateSampleData"
},
"stack": "heroku-18",
"stack": "heroku-20",
"env": {
"DEBUG": {
"required": true
@@ -51,4 +51,4 @@
"url": "heroku/python"
}
]
}
}

View File

@@ -1,6 +1,5 @@
{% extends request.is_ajax|yesno:'base_ajax.html,base_assets.html' %}
{% load widget_tweaks %}
{% block title %}Audit Asset {{ object.asset_id }}{% endblock %}
{% block content %}
<script>

View File

@@ -209,6 +209,8 @@ class AssetAuditList(AssetList):
_errors_selector = (By.CLASS_NAME, "alert-danger")
# Don't use the usual success selector - that tries and fails to hit the '10m long cable' helper button...
_submit_locator = (By.ID, "id_mark_audited")
_close_selector = (By.XPATH, "//button[@data-dismiss='modal']")
form_items = {
'asset_id': (regions.TextBox, (By.ID, 'id_asset_id')),
'description': (regions.TextBox, (By.ID, 'id_description')),
@@ -240,6 +242,10 @@ class AssetAuditList(AssetList):
self.root.find_element(*self._submit_locator).click()
# self.wait.until(lambda x: not self.is_displayed) TODO
def close(self):
previous_errors = self.errors
self.page.find_element(*self._close_selector).click()
def remove_all_required(self):
self.driver.execute_script("Array.from(document.getElementsByTagName(\"input\")).forEach(function (el, ind, arr) { el.removeAttribute(\"required\")});")
self.driver.execute_script("Array.from(document.getElementsByTagName(\"select\")).forEach(function (el, ind, arr) { el.removeAttribute(\"required\")});")

View File

@@ -136,7 +136,7 @@ class TestAssetForm(AutoLoginTest):
self.page.purchased_from_selector.set_option(self.supplier.name, True)
self.page.purchase_price = "12.99"
self.page.salvage_value = "99.12"
self.page.date_acquired = acquired = datetime.date(2020, 5, 20)
self.page.date_acquired = acquired = datetime.date(2020, 5, 2)
self.page.parent_selector.toggle()
self.assertTrue(self.page.parent_selector.is_open)
@@ -294,31 +294,26 @@ class TestAssetAudit(AutoLoginTest):
asset_id = "1111"
self.page.set_query(asset_id)
self.page.search()
mdl = self.page.modal
self.wait.until(EC.visibility_of_element_located((By.ID, 'modal')))
# Do it wrong on purpose to check error display
mdl.remove_all_required()
mdl.description = ""
mdl.submit()
# self.wait.until(EC.visibility_of_element_located((By.ID, 'modal')))
self.page.modal.remove_all_required()
self.page.modal.description = ""
self.page.modal.submit()
self.wait.until(animation_is_finished())
# self.assertTrue(self.driver.find_element_by_id('modal').is_displayed())
self.assertIn("This field is required.", mdl.errors["Description"])
self.assertIn("This field is required.", self.page.modal.errors["Description"])
# Now do it properly
new_desc = "A BIG hammer"
mdl.description = new_desc
mdl.submit()
self.page.modal.description = new_desc = "A BIG hammer"
self.page.modal.submit()
submit_time = timezone.now()
self.wait.until(EC.invisibility_of_element_located((By.ID, 'modal')))
self.assertFalse(self.driver.find_element_by_id('modal').is_displayed())
# Check data is correct
audited = models.Asset.objects.get(asset_id="1111")
audited = models.Asset.objects.get(asset_id=asset_id)
self.assertEqual(audited.description, new_desc)
# Make sure audit 'log' was filled out
self.assertEqual(self.profile.initials, audited.last_audited_by.initials)
self.assertEqual(timezone.now().date(), audited.last_audited_at.date())
self.assertEqual(timezone.now().hour, audited.last_audited_at.hour)
self.assertEqual(timezone.now().minute, audited.last_audited_at.minute)
self.assertEqual(submit_time.replace(microsecond=0), audited.last_audited_at.replace(microsecond=0))
# Check we've removed it from the 'needing audit' list
self.assertNotIn(asset_id, self.page.assets)
@@ -326,18 +321,17 @@ class TestAssetAudit(AutoLoginTest):
self.assertEqual(len(models.Asset.objects.filter(last_audited_at=None)), len(self.page.assets))
asset_row = self.page.assets[0]
self.driver.find_element(By.XPATH, "//*[@id='asset_table_body']/tr[1]/td[4]/a").click()
self.driver.find_element(By.XPATH, "//a[contains(@class,'btn') and contains(., 'Audit')]").click()
self.wait.until(EC.visibility_of_element_located((By.ID, 'modal')))
self.assertEqual(self.page.modal.asset_id, asset_row.id)
# First close button is for the not found error
self.page.find_element(By.XPATH, '//*[@id="modal"]/div/div/div[1]/button').click()
self.page.modal.close()
self.wait.until(EC.invisibility_of_element_located((By.ID, 'modal')))
self.assertFalse(self.driver.find_element_by_id('modal').is_displayed())
# Make sure audit log was NOT filled out
audited = models.Asset.objects.get(asset_id=asset_row.id)
self.assertEqual(None, audited.last_audited_by)
def test_audit_search(self):
# Check that a failed search works
self.page.set_query("NOTFOUND")
self.page.search()
@@ -386,30 +380,31 @@ class Test404(TestCase):
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):
for url in urls.urlpatterns:
if url.name is not None:
pattern = str(url.pattern)
if "json" in url.name or pattern:
# TODO
pass
elif ":pk>" in pattern:
request_url = reverse(url.name, kwargs={'pk': 9})
else:
request_url = reverse(url.name)
response = self.client.get(request_url, HTTP_HOST='example.com')
self.assertEqual(response.status_code, 302)
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.assertEqual(response.status_code, 200)
self.assertContains(response, 'login')
self.assertContains(response, 'Login')
def test_basic_access(self):
self.assertTrue(self.client.login(username="basic", password="basic"))
@@ -455,6 +450,19 @@ class TestAccessLevels(TestCase):
# 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

View File

@@ -211,6 +211,11 @@ class AssetAudit(AssetEdit):
template_name = 'asset_audit.html'
form_class = forms.AssetAuditForm
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["page_title"] = "Audit Asset: {}".format(self.object.display_id)
return context
def get_success_url(self):
# TODO For some reason this doesn't stick when done in form_valid??
asset = self.get_object()

View File

@@ -1,11 +0,0 @@
django:
settings_module: PyRIGS.settings
virtualenv:
envname: myvirtualenv
foreman:
procfile: Procfile
db:
name: postgres_db
user: postgres_db
password: postgres_db

View File

@@ -1,16 +0,0 @@
#!/usr/bin/env bash
# Via https://github.com/kiere/vagrant-heroku-cedar-14/blob/master/config/vagrant/build_dependency_setup.sh
echo "=== Begin Vagrant Provisioning using 'config/vagrant/build_dependency_setup.sh'"
# Install build dependencies for a sane build environment
apt-get -y update
apt-get -y install autoconf bison build-essential libssl-dev libyaml-dev libreadline6-dev zlib1g-dev libncurses5-dev libffi-dev libgdbm3 libgdbm-dev
# Other things that we may need installed before anything else.
apt-get install -y libmemcached-dev
apt-get build-dep python-lxml
echo "=== End Vagrant Provisioning using 'config/vagrant/build_dependency_setup.sh'"

View File

@@ -1,36 +0,0 @@
#!/bin/bash
# Install and (if there's a Procfile) start foreman.
# Needs to come after the virtualenv has been set up.
# Expects three arguments:
VIRTUALENV_NAME=$1
DJANGO_SETTINGS_MODULE=$2
PROCFILE=$3
echo "=== Begin Vagrant Provisioning using 'config/vagrant/foreman_setup.sh'"
gem install foreman --no-ri --no-rdoc
if ! grep -Fq "DJANGO_SETTINGS_MODULE" /home/vagrant/.bashrc; then
echo "export DJANGO_SETTINGS_MODULE=${DJANGO_SETTINGS_MODULE}" >> /home/vagrant/.bashrc
fi
if [[ -f /vagrant/$PROCFILE ]]; then
echo "Procfile found; starting foreman."
export DJANGO_SETTINGS_MODULE="$DJANGO_SETTINGS_MODULE"
# Ensure the virtualenv settings in .profile are loaded:
source /home/vagrant/.profile
# Run with & to release the terminal.
# Although that may also rely on the Procfile's processes having their
# output sent to a file, not stdout/stderr.
foreman start -f /vagrant/$PROCFILE &
else
echo "No Procfile found; not starting foreman."
fi
echo "=== End Vagrant Provisioning using 'config/vagrant/foreman_setup.sh'"

View File

@@ -1,14 +0,0 @@
#!/usr/bin/env bash
# Via https://github.com/kiere/vagrant-heroku-cedar-14/blob/master/config/vagrant/git_setup.sh
echo "=== Begin Vagrant Provisioning using 'config/vagrant/git_setup.sh'"
# Install Git if not available
if [ -z `which git` ]; then
echo "===== Installing Git"
apt-get -y update
apt-get -y install git-core
fi
echo "=== End Vagrant Provisioning using 'config/vagrant/git_setup.sh'"

View File

@@ -1,112 +0,0 @@
#!/bin/sh -e
# Expects three arguments:
# $1 - database name
# $2 - database user
# #3 - database user password
# Via https://github.com/kiere/vagrant-heroku-cedar-14/blob/master/config/vagrant/postgresql_setup.sh
echo "=== Begin Vagrant Provisioning using 'config/vagrant/postgresql_setup.sh'"
APP_DB_NAME=$1
APP_DB_USER=$2
APP_DB_PASS=$3
# Edit the following to change the version of PostgreSQL that is installed
PG_VERSION=9.4
###########################################################
# Changes below this line are probably not necessary
###########################################################
print_db_usage () {
echo "Your PostgreSQL database has been setup and can be accessed on your local machine on the forwarded port (default: 15432)"
echo " Host: localhost"
echo " Port: 15432"
echo " Database: $APP_DB_NAME"
echo " Username: $APP_DB_USER"
echo " Password: $APP_DB_PASS"
echo ""
echo "Admin access to postgres user via VM:"
echo " vagrant ssh"
echo " sudo su - postgres"
echo ""
echo "psql access to app database user via VM:"
echo " vagrant ssh"
echo " sudo su - postgres"
echo " PGUSER=$APP_DB_USER PGPASSWORD=$APP_DB_PASS psql -h localhost $APP_DB_NAME"
echo ""
echo "Env variable for application development:"
echo " DATABASE_URL=postgresql://$APP_DB_USER:$APP_DB_PASS@localhost:15432/$APP_DB_NAME"
echo ""
echo "Local command to access the database via psql:"
echo " PGUSER=$APP_DB_USER PGPASSWORD=$APP_DB_PASS psql -h localhost -p 15432 $APP_DB_NAME"
}
export DEBIAN_FRONTEND=noninteractive
PROVISIONED_ON=/etc/vm_provision_on_timestamp
if [ -f "$PROVISIONED_ON" ]
then
echo "VM was already provisioned at: $(cat $PROVISIONED_ON)"
echo "To run system updates manually login via 'vagrant ssh' and run 'apt-get update && apt-get upgrade'"
echo ""
print_db_usage
exit
fi
PG_REPO_APT_SOURCE=/etc/apt/sources.list.d/pgdg.list
if [ ! -f "$PG_REPO_APT_SOURCE" ]
then
# Add PG apt repo:
echo "deb http://apt.postgresql.org/pub/repos/apt/ precise-pgdg main" > "$PG_REPO_APT_SOURCE"
# Add PGDG repo key:
wget --quiet -O - http://apt.postgresql.org/pub/repos/apt/ACCC4CF8.asc | apt-key add -
fi
# Update package list and upgrade all packages
apt-get update
apt-get -y upgrade
apt-get -y install "postgresql-$PG_VERSION" "postgresql-contrib-$PG_VERSION"
apt-get -y install libpq-dev # For building ruby 'pg' gem
PG_CONF="/etc/postgresql/$PG_VERSION/main/postgresql.conf"
PG_HBA="/etc/postgresql/$PG_VERSION/main/pg_hba.conf"
PG_DIR="/var/lib/postgresql/$PG_VERSION/main"
# Edit postgresql.conf to change listen address to '*':
sed -i "s/#listen_addresses = 'localhost'/listen_addresses = '*'/" "$PG_CONF"
# Append to pg_hba.conf to add password auth:
echo "host all all all md5" >> "$PG_HBA"
# Explicitly set default client_encoding
echo "client_encoding = utf8" >> "$PG_CONF"
# Restart so that all new config is loaded:
service postgresql restart
cat << EOF | su - postgres -c psql
-- Create the database user:
CREATE USER $APP_DB_USER PASSWORD '$APP_DB_PASS';
EOF
cat << EOF | su - postgres -c psql
-- Create the database:
CREATE DATABASE $APP_DB_NAME WITH OWNER=$APP_DB_USER
LC_COLLATE='en_US.utf8'
LC_CTYPE='en_US.utf8'
ENCODING='UTF8'
TEMPLATE=template0;
EOF
# Tag the provision time:
date > "$PROVISIONED_ON"
echo "Successfully created PostgreSQL dev virtual machine."
echo ""
print_db_usage
echo "=== End Vagrant Provisioning using 'config/vagrant/postgresql_setup.sh'"

View File

@@ -1,23 +0,0 @@
#!/bin/bash
# Install python and required python modules.
# pip and virtualenv are in virtualenv_setup.sh
# Initial part of this via
# https://github.com/torchbox/vagrant-django-base/blob/master/install.sh
echo "=== Begin Vagrant Provisioning using 'config/vagrant/python_setup.sh'"
apt-get update -y
# Python dev packages
apt-get install -y python python-dev python-setuptools python-pip
# Dependencies for image processing with Pillow (drop-in replacement for PIL)
# supporting: jpeg, tiff, png, freetype, littlecms
apt-get install -y libjpeg-dev libtiff-dev zlib1g-dev libfreetype6-dev liblcms2-dev
# lxml dependencies
apt-get install -y libxml2-dev libxslt1-dev python-dev
echo "=== End Vagrant Provisioning using 'config/vagrant/python_setup.sh'"

View File

@@ -1,66 +0,0 @@
#!/bin/bash
# This will:
# * Install pip, virtualenv and virtualenvwrapper.
# * Set up virtualenvwrapper's paths etc.
# * Create a new virtualenv.
# * Install any pip requirements from the requirements.txt file.
# Expects one argument, the name of the virtualenv.
# The name we'll use for the virtualenv in which we'll install requirements:
VENV_NAME=$1
echo "=== Begin Vagrant Provisioning using 'config/vagrant/virtualenv_setup.sh'"
# virtualenv global setup
if ! command -v pip; then
easy_install -U pip
fi
if [[ ! -f /usr/local/bin/virtualenv ]]; then
easy_install virtualenv virtualenvwrapper
fi
# If it doesn't look like .bashrc has the required virtualenvwrapper lines in,
# then add them.
if ! grep -Fq "WORKON_HOME" /home/vagrant/.profile; then
echo "Adding virtualenvwrapper locations to .profile"
if [[ -d /vagrant/config/virtualenvwrapper/vagrant ]]; then
echo "export VIRTUALENVWRAPPER_HOOK_DIR=/vagrant/config/virtualenvwrapper/vagrant" >> /home/vagrant/.profile
fi
echo "export WORKON_HOME=/home/vagrant/.virtualenvs" >> /home/vagrant/.profile
echo "export PROJECT_HOME=/home/vagrant/Devel" >> /home/vagrant/.profile
echo "source /usr/local/bin/virtualenvwrapper.sh" >> /home/vagrant/.profile
fi
# Get .virtualenvwrapper env variables set up:
source /home/vagrant/.profile
if [[ -d /home/vagrant/.virtualenvs/$VENV_NAME ]]; then
echo "Activating virtualenv $VENV_NAME."
workon $VENV_NAME
else
echo "Making new virtualenv $VENV_NAME."
# Also switches to the virtualenv:
mkvirtualenv $VENV_NAME
# So that we can install things with pip while ssh'd in as vagrant user:
sudo chown -R vagrant:vagrant /home/vagrant/.virtualenvs/$VENV_NAME/
# Automatically switch to the virtual env on log in:
echo "workon $VENV_NAME" >> /home/vagrant/.profile
fi
# If we have a requirements.txt file in this project, then install
# everything in it with pip in a new virtualenv.
if [[ -f /vagrant/requirements.txt ]]; then
echo "Installing from ./requirements.txt with pip."
pip install -r /vagrant/requirements.txt
fi
echo "=== End Vagrant Provisioning using 'config/vagrant/virtualenv_setup.sh'"

9827
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,7 +3,7 @@
"version": "1.0.0",
"repository": "https://github.com/nottinghamtec/PyRIGS",
"author": "Tom Price",
"license": "MIT",
"license": "Custom",
"dependencies": {
"@forevolve/bootstrap-dark": "^1.0.0-alpha.1075",
"@fortawesome/fontawesome-free": "^5.13.1",
@@ -16,8 +16,6 @@
"dark-mode-switch": "^1.0.0",
"flatpickr": "^4.6.6",
"fullcalendar": "^5.3.2",
"gulp-if": "^3.0.0",
"gulp-rename": "^2.0.0",
"jquery": "^3.5.1",
"jquery-ui-dist": "^1.12.1",
"konami": "^1.6.2",
@@ -30,7 +28,9 @@
"gulp": "^4.0.2",
"gulp-clean-css": "^4.3.0",
"gulp-flatten": "^0.4.0",
"gulp-if": "^3.0.0",
"gulp-postcss": "^8.0.0",
"gulp-rename": "^2.0.0",
"gulp-sass": "^4.1.0",
"gulp-sourcemaps": "^2.6.5",
"gulp-terser": "^1.2.0",

View File

@@ -1,21 +1,20 @@
ansicolors==1.1.8
asgiref==3.2.10
asgiref==3.3.1
backports.tempfile==1.0
backports.weakref==1.0.post1
beautifulsoup4==4.9.3
cachetools==4.1.1
certifi==2020.6.20
chardet==3.0.4
cachetools==4.2.1
certifi==2020.12.5
chardet==4.0.0
configparser==5.0.1
contextlib2==0.6.0.post1
coverage==5.3
cssselect==1.1.0
cssutils==1.0.2
diff-match-patch==20200713
dj-database-url==0.5.0
dj-static==0.0.6
Django==3.1.2
django-debug-toolbar==3.1.1
Django==3.1.5
django-debug-toolbar==3.2
django-filter==2.4.0
django-gulp==4.1.0
django-ical==1.7.1
@@ -23,58 +22,57 @@ django-livereload==1.7
django-livereload-server==0.3.2
django-recaptcha==2.0.6
django-recurrence==1.10.3
django-registration-redux==2.8
django-reversion==3.0.8
django-registration-redux==2.9
django-reversion==3.0.9
django-toolbelt==0.0.1
django-widget-tweaks==1.4.8
env-tools==2.2.0
envparse==0.2.0
gunicorn==20.0.4
icalendar==4.0.7
idna==2.10
imgurpython==1.1.7
importlib-metadata==2.0.0
lxml==4.5.2
Markdown==3.3
msgpack==1.0.0
packaging==20.4
pep517==0.8.2
Pillow==7.2.0
importlib-metadata==3.4.0
lxml==4.6.2
Markdown==3.3.3
msgpack==1.0.2
packaging==20.8
pep517==0.9.1
Pillow==8.1.0
pluggy==0.13.1
premailer==3.7.0
progress==1.5
psutil==5.7.2
psutil==5.8.0
psycopg2==2.8.6
psycopg2-binary==2.8.6
Pygments==2.7.1
Pygments==2.7.4
pyparsing==2.4.7
PyPDF2==1.26.0
PyPOM==2.2.0
python-dateutil==2.8.1
pytoml==0.1.21
pytz==2020.1
pytz==2020.5
raven==6.10.0
reportlab==3.5.53
requests==2.24.0
reportlab==3.5.60
requests==2.25.1
retrying==1.3.3
selenium==3.141.0
simplejson==3.17.2
six==1.15.0
soupsieve==2.0.1
soupsieve==2.1
sqlparse==0.4.1
static3==0.7.0
svg2rlg==0.3
tini==3.0.1
tornado==6.0.4
urllib3==1.25.10
tornado==6.1
urllib3==1.26.2
whitenoise==5.2.0
yolk==0.4.3
z3c.rml==3.10.0
zipp==3.3.0
z3c.rml==4.1.2
zipp==3.4.0
zope.component==4.6.2
zope.deferredimport==4.3.1
zope.deprecation==4.4.0
zope.event==4.5.0
zope.hookable==5.0.1
zope.interface==5.1.2
zope.interface==5.2.0
zope.proxy==4.3.5
zope.schema==6.0.0
zope.schema==6.0.1

View File

@@ -1 +1 @@
python-3.8.2
python-3.9.1