mirror of
https://github.com/nottinghamtec/PyRIGS.git
synced 2026-02-09 08:19:41 +00:00
Compare commits
30 Commits
imgbot
...
12c4b63947
| Author | SHA1 | Date | |
|---|---|---|---|
| 12c4b63947 | |||
| 39ab9df836 | |||
| a99e4b1d1c | |||
| 18a091f8ea | |||
| d64d0f54d4 | |||
| 8f54897b69 | |||
| 97830596b5 | |||
| 68f401097d | |||
| 8c5b2f426d | |||
| e3fc05772e | |||
| e38205b9e7 | |||
| f2b9642772 | |||
| 08939a0e1f | |||
| 15b7f9c7c1 | |||
| c67f7e1e54 | |||
| 4f268b3168 | |||
| 0e7723828a | |||
| c46a2c53f3 | |||
| b3617a74bf | |||
| 5806cbc72d | |||
| ab2ff9f146 | |||
| fd5575a818 | |||
| 402a1dd7f0 | |||
| be7688aa75 | |||
| a472e414f7 | |||
| 618c02aa9c | |||
| 3056b6ef71 | |||
| 548c960996 | |||
| 2cc43dcdb7 | |||
| 6db25fb56b |
@@ -6,3 +6,4 @@ plugins =
|
||||
|
||||
omit =
|
||||
*/migrations/*
|
||||
*/tests/*
|
||||
|
||||
55
.github/workflows/django.yml
vendored
55
.github/workflows/django.yml
vendored
@@ -9,22 +9,31 @@ on:
|
||||
jobs:
|
||||
build:
|
||||
env:
|
||||
IMGUR_UPLOAD_CLIENT_ID: ${{ secrets.IMGUR_UPLOAD_CLIENT_ID }}
|
||||
IMGUR_UPLOAD_CLIENT_SECRET: ${{ secrets.IMGUR_UPLOAD_CLIENT_SECRET }}
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
runs-on: ubuntu-latest
|
||||
if: "!contains(github.event.head_commit.message, '[ci skip]')"
|
||||
strategy:
|
||||
max-parallel: 1
|
||||
matrix:
|
||||
python-version: [3.8]
|
||||
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 ${{ matrix.python-version }}
|
||||
- name: Set up Python
|
||||
uses: actions/setup-python@v2
|
||||
with:
|
||||
python-version: ${{ matrix.python-version }}
|
||||
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
|
||||
@@ -35,7 +44,7 @@ jobs:
|
||||
run: |
|
||||
python -m pip install --upgrade pip
|
||||
pip install pycodestyle coverage coveralls django_coverage_plugin
|
||||
pip install -r requirements.txt
|
||||
pip install --upgrade --upgrade-strategy eager -r requirements.txt
|
||||
python manage.py collectstatic --noinput
|
||||
- name: Basic Checks
|
||||
run: |
|
||||
@@ -43,6 +52,32 @@ jobs:
|
||||
python manage.py check
|
||||
python manage.py makemigrations --check --dry-run
|
||||
- name: Run Tests
|
||||
run: |
|
||||
coverage run manage.py test --verbosity=2
|
||||
coveralls --service=github
|
||||
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
1
.idea/.name
generated
@@ -1 +0,0 @@
|
||||
PyRIGS
|
||||
5
.idea/encodings.xml
generated
5
.idea/encodings.xml
generated
@@ -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
8
.idea/modules.xml
generated
@@ -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>
|
||||
5
.idea/scopes/scope_settings.xml
generated
5
.idea/scopes/scope_settings.xml
generated
@@ -1,5 +0,0 @@
|
||||
<component name="DependencyValidationManager">
|
||||
<state>
|
||||
<option name="SKIP_IMPORT_STATEMENTS" value="false" />
|
||||
</state>
|
||||
</component>
|
||||
7
.idea/vcs.xml
generated
7
.idea/vcs.xml
generated
@@ -1,7 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
||||
|
||||
1156
.rubocop.yml
1156
.rubocop.yml
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,3 @@
|
||||
*.sqlite3
|
||||
*.scss
|
||||
*.md
|
||||
*.rb
|
||||
Vagrantfile
|
||||
config/vagrant/*
|
||||
config/vagrant.yml
|
||||
|
||||
@@ -263,6 +263,3 @@ USE_GRAVATAR = True
|
||||
|
||||
TERMS_OF_HIRE_URL = "http://www.nottinghamtec.co.uk/terms.pdf"
|
||||
AUTHORISATION_NOTIFICATION_ADDRESS = 'productions@nottinghamtec.co.uk'
|
||||
|
||||
IMGUR_UPLOAD_CLIENT_ID = env('IMGUR_UPLOAD_CLIENT_ID', default="")
|
||||
IMGUR_UPLOAD_CLIENT_SECRET = env('IMGUR_UPLOAD_CLIENT_SECRET', default="")
|
||||
|
||||
@@ -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,9 +20,6 @@ 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")
|
||||
options.add_argument("--headless")
|
||||
if settings.CI:
|
||||
options.add_argument("--no-sandbox")
|
||||
@@ -62,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
|
||||
|
||||
|
||||
4
RIGS/static/css/bootstrap-select.css
vendored
4
RIGS/static/css/bootstrap-select.css
vendored
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
@@ -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
4
RIGS/static/js/bootstrap-select.js
vendored
4
RIGS/static/js/bootstrap-select.js
vendored
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
4
RIGS/static/js/flatpickr.min.js
vendored
4
RIGS/static/js/flatpickr.min.js
vendored
File diff suppressed because one or more lines are too long
24
RIGS/static/js/jquery-ui.js
vendored
24
RIGS/static/js/jquery-ui.js
vendored
File diff suppressed because one or more lines are too long
4
RIGS/static/js/jquery.js
vendored
4
RIGS/static/js/jquery.js
vendored
File diff suppressed because one or more lines are too long
4
RIGS/static/js/main.min.js
vendored
4
RIGS/static/js/main.min.js
vendored
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
@@ -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
@@ -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}));
|
||||
@@ -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()
|
||||
|
||||
@@ -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
134
Vagrantfile
vendored
@@ -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
|
||||
4
app.json
4
app.json
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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\")});")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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'"
|
||||
|
||||
@@ -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'"
|
||||
@@ -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'"
|
||||
@@ -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'"
|
||||
@@ -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'"
|
||||
@@ -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
9827
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -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",
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
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
|
||||
cssselect==1.1.0
|
||||
@@ -13,8 +13,8 @@ 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
|
||||
@@ -22,59 +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
|
||||
envparse==0.2.0
|
||||
env-tools==2.2.0
|
||||
gunicorn==20.0.4
|
||||
icalendar==4.0.7
|
||||
idna==2.10
|
||||
imgurpython==1.1.7
|
||||
importlib-metadata==2.0.0
|
||||
importlib-metadata==3.4.0
|
||||
lxml==4.6.2
|
||||
Markdown==3.3
|
||||
msgpack==1.0.0
|
||||
packaging==20.4
|
||||
pep517==0.8.2
|
||||
Pillow==7.2.0
|
||||
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
|
||||
|
||||
@@ -1 +1 @@
|
||||
python-3.8.2
|
||||
python-3.9.1
|
||||
|
||||
Reference in New Issue
Block a user