Compare commits
306 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 06723e3f69 | |||
| ba9b5d02b2 | |||
| 242d143a5e | |||
| 2bf19d357e | |||
| 7e31f72301 | |||
| 68bb003411 | |||
| 7133f36e5d | |||
| c9962c4d8e | |||
| 5832bd1765 | |||
| 4046d2c753 | |||
| 93298618ae | |||
| 709a637ae2 | |||
| a88bb30b62 | |||
| 38527207ac | |||
| 6f90fcc016 | |||
| 1e633ded31 | |||
| 4b3b8be4e4 | |||
| effd58a424 | |||
| 850587006c | |||
| 423b574cca | |||
| 7bb4a6cfc1 | |||
| 94f392ab87 | |||
| ccef40e63f | |||
| 1c51b666ab | |||
| b5462d5757 | |||
| 587632d7a3 | |||
| 11c92cdd5f | |||
| e4577e13e0 | |||
| 6365e0c63e | |||
| 4735541344 | |||
| 8e40434867 | |||
| 8194ab43cd | |||
| a708a6377d | |||
| 3fc810697a | |||
| 3305704926 | |||
| 206ec80a9a | |||
| dce19b8d38 | |||
| 8a8751ce66 | |||
| 0f0389b8ff | |||
| 061c9c8483 | |||
| 005d34daf5 | |||
| 95e028d546 | |||
| 95c29d8528 | |||
| bda342b05b | |||
| 889ad4f980 | |||
| a5bca8eab1 | |||
| 2dfb53bd5e | |||
| 474df33a99 | |||
| a2906966ba | |||
| a81096fa13 | |||
| b56ff6c5cd | |||
| 168de8088b | |||
| e7862df57c | |||
| ec829a5683 | |||
| bb3476a8ad | |||
| bab5c88061 | |||
| 7431aadfba | |||
| 1ecf3c368b | |||
| d3e6013840 | |||
| e1220d17bb | |||
| 55fdf8f60d | |||
| 65aac3daf1 | |||
| 1f8e9e582a | |||
| 97e6ce3d8d | |||
| 316ab679f8 | |||
| bf5620c3b6 | |||
| 642aa9847f | |||
| 90f430c95c | |||
| bf4c5bf3d9 | |||
| b7beb72409 | |||
| 0617dd6a93 | |||
| d99f9c53f7 | |||
| 3cfa0df43b | |||
| dc2982965e | |||
| 3c58d764bd | |||
| 4d2584dee4 | |||
| 3294d6ffa0 | |||
| 8398928a97 | |||
| 09a2e09c1b | |||
| d0f5bc223b | |||
| 7a58fb0af5 | |||
| 395c597a7f | |||
| e43734e32e | |||
| eb5659d0da | |||
| 50268b98a9 | |||
| 4a2a5f9d76 | |||
| ef6b8ed5a5 | |||
| b1eda70e7a | |||
| 2ae9ee7352 | |||
| f7b00ab3cc | |||
| 9cad12d879 | |||
| 5967d0f7b3 | |||
| d4800c449d | |||
| 8f9c504bec | |||
| d3d4ce5e5d | |||
| 9dbc2424b1 | |||
| 32771493f3 | |||
| 5b38065f13 | |||
| 1879c265cd | |||
| c654c41380 | |||
| 4273b95b70 | |||
| e4cffd5667 | |||
| e96698ef2e | |||
| e04b8ddb9b | |||
| 6fe3e69cd9 | |||
| 7d1a8bd284 | |||
| 5b44d2e4c7 | |||
| fa0954e8ca | |||
| 8552bde245 | |||
| 9a4d7fc498 | |||
| 6dea241408 | |||
| b3b1bec12c | |||
| 02cc305abf | |||
| ffe0c45eea | |||
| 499ddc0979 | |||
| b154ffb79e | |||
| 87dfab0e57 | |||
| 92ec8b1b4e | |||
| ac8fb0bfe3 | |||
| 0ce6af8f7c | |||
| 053b705cc1 | |||
| 3676f23f65 | |||
| 7e821f277f | |||
| 91cbdef71f | |||
| 0cfb78bc69 | |||
| 01c20b1a6e | |||
| 1711aca5ec | |||
| c536899cc9 | |||
| 60da9d8256 | |||
| a923e225e8 | |||
| 2d7c9d779a | |||
| aea9898563 | |||
| 4e3f71ea43 | |||
| 6acbdbc760 | |||
| 11b6e68fe1 | |||
| cc3aa66e49 | |||
| 563344e8b4 | |||
| 129b8e4601 | |||
| efde69984d | |||
| c66c8e7367 | |||
| c31f454c78 | |||
| 18926d16d1 | |||
| 4e8adebb2d | |||
| 0207bdf22b | |||
| 5caacd8f44 | |||
| d7a3433d2c | |||
| 6e68e106aa | |||
| aeda06374d | |||
| 9225ff5967 | |||
| ac64a1766f | |||
| 6996bb8015 | |||
| 7aff7c46ee | |||
| 882732d054 | |||
| 9e0d911f7b | |||
| ab6b7d19fb | |||
| b95be67051 | |||
| 48b6ed5b69 | |||
| e25041d38d | |||
| 7bc77ef232 | |||
| 0f8a7d76da | |||
| ecf34d9039 | |||
| a9cf253c83 | |||
| 884c2552a8 | |||
| 45e98e0220 | |||
| d8ea26c777 | |||
| c398e53750 | |||
| 9ce0eccfce | |||
| 17e6bb86ed | |||
| a1b85b3c6c | |||
| fafc988a60 | |||
| 55bcc78670 | |||
| 7bc277a978 | |||
| 780e2d6acb | |||
| bbc5743c39 | |||
| f9082237e6 | |||
| 3298e55fb0 | |||
| 2b2d20f796 | |||
| a72b313b83 | |||
| 117802bf10 | |||
| 94f8a92e65 | |||
| 8bd53ba897 | |||
| 5114b2ef85 | |||
| f80cbd7457 | |||
| d7f53b9700 | |||
| 1ab3180c0d | |||
| 009495b11b | |||
| b8a8cb2c6d | |||
| f9bb4bba25 | |||
| a56e8ef241 | |||
| d5d11edbe7 | |||
| f7c2516cd7 | |||
| 45b27e3ac9 | |||
| fe71f24ced | |||
| 52613ba7d4 | |||
| af2719082e | |||
| f136b34b6c | |||
| 4d90454cf8 | |||
| 82e0c5c995 | |||
| dec3bf5ccf | |||
| 23c00ce167 | |||
| bdc21f79e8 | |||
| 2fc71eabe3 | |||
| 3debd4b1ec | |||
| b765ae37e8 | |||
| 9eae16110c | |||
| ce1f4eb7c9 | |||
| 661dc84973 | |||
| 6b21ea4af8 | |||
| 37ab278086 | |||
| 509b157d65 | |||
| 253f720043 | |||
| bdf6b469ad | |||
| 7dc9fac597 | |||
| 77330dffe9 | |||
| f0ea3505e4 | |||
| 06c2a2b9a6 | |||
| c671206e8a | |||
| cf50050eba | |||
| f8e68acd4d | |||
| 9b6fc5e687 | |||
| 7d17d8a84f | |||
| b2aa6d1a3e | |||
| 5a2c6d9aaa | |||
| 1ecbda0731 | |||
| 9e9049709b | |||
| ac9a5db356 | |||
| 67ed7edefb | |||
| 181be6b80c | |||
| 1e2bf10494 | |||
| a219b930b3 | |||
| 78ba2d7afa | |||
| 6fe01dadf1 | |||
| 9df62a1247 | |||
| a9164f8c6e | |||
| 6e5074f8fe | |||
| efe8808e79 | |||
| 77cdce714a | |||
| 69c1b2dcb2 | |||
| 2a50f7ef43 | |||
| 0c93446b81 | |||
| 0e52efb449 | |||
| 283d5b566e | |||
| a4367bbc9d | |||
| 935f7a38f1 | |||
| 9973057051 | |||
| 9527e6de5f | |||
| 86e2827f3b | |||
| a519d51309 | |||
| 9ee4d600a7 | |||
| 2b2d635cb0 | |||
| ec6051d3d6 | |||
| 5479f0e1a7 | |||
| c219f32266 | |||
| e111d1884c | |||
| 7554750883 | |||
| e75f0cfc67 | |||
| 7d3208651a | |||
| e949e93799 | |||
| f544cf6183 | |||
| 197c7b0a8b | |||
| abb3f6659d | |||
| 8141ccfa13 | |||
| f395e8de06 | |||
| 7614c127ba | |||
| b2cc29f6af | |||
| 7efb8d3e7b | |||
| 48fa13e37b | |||
| d5ead73869 | |||
| a81f305e54 | |||
| dcef7aa49a | |||
| e0f571a201 | |||
| e5e9774681 | |||
| 6f18fa0aea | |||
| 9a918da2f0 | |||
| 17d1d4fea2 | |||
| 85fcf6feb9 | |||
| 89665d2b48 | |||
| c3478ff47c | |||
| b77dd3f50e | |||
| 7009f38652 | |||
| 4ff426327b | |||
| d7d0b377f2 | |||
| 4f499af4cf | |||
| d9ed6e7b17 | |||
| efbfe64d1e | |||
| cc9794d6a8 | |||
| 19ff70d0bd | |||
| d82e3ec4d9 | |||
| d0825e96bc | |||
| a981f6a31f | |||
| 524c6bbb9e | |||
| ac4902f867 | |||
| 416be8e2cd | |||
| 4cee5582da | |||
| 160f5adc59 | |||
| b8267e411c | |||
| ab2fcf04eb | |||
| 4a79ed341e | |||
| 7b8c5f3d8f | |||
| 170635a8db | |||
| a86f71b422 | |||
| 2585c4885b | |||
| 1cba13f4ff | |||
| 63e669ff0c | |||
| 2d95dbb0f1 | |||
| 8f50a6e0bf |
@@ -1,3 +1,5 @@
|
||||
[report]
|
||||
show_missing = True
|
||||
[run]
|
||||
omit =
|
||||
*/migrations/*
|
||||
|
||||
@@ -3,3 +3,4 @@ infoscreen/static/js/lib
|
||||
webapp/static/js/lib
|
||||
static/js/lib
|
||||
collected_static
|
||||
venv
|
||||
|
||||
@@ -5,7 +5,6 @@ sikweb/settings.py
|
||||
*.sqlite3
|
||||
uwsgi.ini
|
||||
uwsgi.log
|
||||
infoscreen/static/js/hsl.json
|
||||
members/logs/*
|
||||
.idea/
|
||||
logs/
|
||||
@@ -17,4 +16,8 @@ requirements_henu.txt
|
||||
/collected_static/
|
||||
mydatabase
|
||||
settings.json
|
||||
.vscode/
|
||||
.vscode/
|
||||
.DS_Store
|
||||
*.code-workspace
|
||||
sik_test
|
||||
venv/
|
||||
@@ -31,7 +31,7 @@ pycodestyle:
|
||||
- pycodestyle --config=setup.cfg --count .
|
||||
|
||||
eslint:
|
||||
image: node:7.10.0
|
||||
image: node:alpine
|
||||
stage: lint
|
||||
before_script:
|
||||
- npm install
|
||||
@@ -39,7 +39,7 @@ eslint:
|
||||
- npm run eslint
|
||||
|
||||
remark:
|
||||
image: node:7.10.0
|
||||
image: node:alpine
|
||||
stage: lint
|
||||
before_script:
|
||||
- npm install
|
||||
@@ -48,13 +48,14 @@ remark:
|
||||
|
||||
publish:
|
||||
stage: publish
|
||||
image: docker:latest
|
||||
image: docker:stable
|
||||
services:
|
||||
- docker:stable-dind
|
||||
only:
|
||||
- develop
|
||||
before_script:
|
||||
- docker info
|
||||
- docker login -u gitlab-ci-token -p $CI_BUILD_TOKEN $REGISTRY_URL
|
||||
script:
|
||||
- docker info
|
||||
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
|
||||
- docker build . -t "$IMAGE_NAME"
|
||||
- docker push "$IMAGE_NAME"
|
||||
|
||||
@@ -63,7 +64,7 @@ deploy_dev:
|
||||
image: alpine:latest
|
||||
environment:
|
||||
name: dev
|
||||
url: http://web.sik.party:8080
|
||||
url: http://web.sik.party:8000
|
||||
only:
|
||||
- develop
|
||||
before_script:
|
||||
@@ -77,6 +78,7 @@ deploy_dev:
|
||||
script:
|
||||
- scp docker-compose.yml $DEV_SSH_USER@$DEV_SSH_HOST:~/deployment/docker-compose.yml
|
||||
- scp .deploy_dev.sh $DEV_SSH_USER@$DEV_SSH_HOST:~/deployment/deploy_dev.sh
|
||||
- ssh $DEV_SSH_USER@$DEV_SSH_HOST "docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY"
|
||||
- ssh $DEV_SSH_USER@$DEV_SSH_HOST "bash ~/deployment/deploy_dev.sh \"$IMAGE_NAME\""
|
||||
|
||||
deploy_production:
|
||||
@@ -98,4 +100,3 @@ deploy_production:
|
||||
- echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
|
||||
script:
|
||||
- ssh $PROD_SSH_USER@$PROD_SSH_HOST "zsh ~/deploy.sh"
|
||||
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
3.6.8
|
||||
@@ -1,4 +1,4 @@
|
||||
FROM python:3
|
||||
FROM python:3.5
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
ENV IS_DOCKER 1
|
||||
RUN mkdir /code
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
[[source]]
|
||||
name = "pypi"
|
||||
url = "https://pypi.org/simple"
|
||||
verify_ssl = true
|
||||
|
||||
[dev-packages]
|
||||
flake8 = "*"
|
||||
autopep8 = "*"
|
||||
|
||||
[packages]
|
||||
decorator = "==4.0.9"
|
||||
ipython = "==4.2.0"
|
||||
pexpect = "==4.1.0"
|
||||
pickleshare = "==0.7.2"
|
||||
ptyprocess = "==0.5.1"
|
||||
pytz = "==2016.4"
|
||||
simplegeneric = "==0.8.1"
|
||||
traitlets = "==4.2.1"
|
||||
requests = "==2.11.1"
|
||||
django-nocaptcha-recaptcha = "==0.0.19"
|
||||
django-cors-headers = "==2.0.1"
|
||||
djangorestframework = "==3.8.2"
|
||||
djangorestframework-jwt = "==1.11.0"
|
||||
coverage = "==4.3.4"
|
||||
django-nose = "==1.4.5"
|
||||
nose-exclude = "==0.5.0"
|
||||
psycopg2-binary = "==2.7.6.1"
|
||||
django-bootstrap3 = "==8.2.3"
|
||||
django-tables2 = "==1.6.1"
|
||||
pycodestyle = "==2.3.1"
|
||||
dealer = "==2.0.5"
|
||||
django-modeltranslation = "==0.13b1"
|
||||
django-auditlog = "==0.4.5"
|
||||
django-phonenumber-field = "==1.3.0"
|
||||
django-autocomplete-light = "==3.2.10"
|
||||
six = "==1.10.0"
|
||||
django-suit = "==0.2.26"
|
||||
telepot = "==12.3"
|
||||
pyexcel = "==0.5.10"
|
||||
pyexcel-xlsx = "==0.5.5"
|
||||
django-import-export = "==0.7.0"
|
||||
openpyxl = "==2.4.11"
|
||||
django-app-namespace-template-loader = "==0.4.1"
|
||||
django-filter = "==2.0.0"
|
||||
"backports.shutil_get_terminal_size" = "==1.0.0"
|
||||
Django = "==2.1.5"
|
||||
ipython_genutils = "==0.1.0"
|
||||
Pillow = "==5.4.1"
|
||||
PyJWT = "==1.6.4"
|
||||
|
||||
[requires]
|
||||
python_version = "3.6"
|
||||
@@ -0,0 +1,706 @@
|
||||
{
|
||||
"_meta": {
|
||||
"hash": {
|
||||
"sha256": "fd7aa96e8c4fc9e3fa88b6f3b28a1101d7efd8b58e964fbece854850acf8bcea"
|
||||
},
|
||||
"pipfile-spec": 6,
|
||||
"requires": {
|
||||
"python_version": "3.6"
|
||||
},
|
||||
"sources": [
|
||||
{
|
||||
"name": "pypi",
|
||||
"url": "https://pypi.org/simple",
|
||||
"verify_ssl": true
|
||||
}
|
||||
]
|
||||
},
|
||||
"default": {
|
||||
"aiohttp": {
|
||||
"hashes": [
|
||||
"sha256:00d198585474299c9c3b4f1d5de1a576cc230d562abc5e4a0e81d71a20a6ca55",
|
||||
"sha256:0155af66de8c21b8dba4992aaeeabf55503caefae00067a3b1139f86d0ec50ed",
|
||||
"sha256:09654a9eca62d1bd6d64aa44db2498f60a5c1e0ac4750953fdd79d5c88955e10",
|
||||
"sha256:199f1d106e2b44b6dacdf6f9245493c7d716b01d0b7fbe1959318ba4dc64d1f5",
|
||||
"sha256:296f30dedc9f4b9e7a301e5cc963012264112d78a1d3094cd83ef148fdf33ca1",
|
||||
"sha256:368ed312550bd663ce84dc4b032a962fcb3c7cae099dbbd48663afc305e3b939",
|
||||
"sha256:40d7ea570b88db017c51392349cf99b7aefaaddd19d2c78368aeb0bddde9d390",
|
||||
"sha256:629102a193162e37102c50713e2e31dc9a2fe7ac5e481da83e5bb3c0cee700aa",
|
||||
"sha256:6d5ec9b8948c3d957e75ea14d41e9330e1ac3fed24ec53766c780f82805140dc",
|
||||
"sha256:87331d1d6810214085a50749160196391a712a13336cd02ce1c3ea3d05bcf8d5",
|
||||
"sha256:9a02a04bbe581c8605ac423ba3a74999ec9d8bce7ae37977a3d38680f5780b6d",
|
||||
"sha256:9c4c83f4fa1938377da32bc2d59379025ceeee8e24b89f72fcbccd8ca22dc9bf",
|
||||
"sha256:9cddaff94c0135ee627213ac6ca6d05724bfe6e7a356e5e09ec57bd3249510f6",
|
||||
"sha256:a25237abf327530d9561ef751eef9511ab56fd9431023ca6f4803f1994104d72",
|
||||
"sha256:a5cbd7157b0e383738b8e29d6e556fde8726823dae0e348952a61742b21aeb12",
|
||||
"sha256:a97a516e02b726e089cffcde2eea0d3258450389bbac48cbe89e0f0b6e7b0366",
|
||||
"sha256:acc89b29b5f4e2332d65cd1b7d10c609a75b88ef8925d487a611ca788432dfa4",
|
||||
"sha256:b05bd85cc99b06740aad3629c2585bda7b83bd86e080b44ba47faf905fdf1300",
|
||||
"sha256:c2bec436a2b5dafe5eaeb297c03711074d46b6eb236d002c13c42f25c4a8ce9d",
|
||||
"sha256:cc619d974c8c11fe84527e4b5e1c07238799a8c29ea1c1285149170524ba9303",
|
||||
"sha256:d4392defd4648badaa42b3e101080ae3313e8f4787cb517efd3f5b8157eaefd6",
|
||||
"sha256:e1c3c582ee11af7f63a34a46f0448fca58e59889396ffdae1f482085061a2889"
|
||||
],
|
||||
"version": "==3.5.4"
|
||||
},
|
||||
"async-timeout": {
|
||||
"hashes": [
|
||||
"sha256:0c3c816a028d47f659d6ff5c745cb2acf1f966da1fe5c19c77a70282b25f4c5f",
|
||||
"sha256:4291ca197d287d274d0b6cb5d6f8f8f82d434ed288f962539ff18cc9012f9ea3"
|
||||
],
|
||||
"version": "==3.0.1"
|
||||
},
|
||||
"attrs": {
|
||||
"hashes": [
|
||||
"sha256:69c0dbf2ed392de1cb5ec704444b08a5ef81680a61cb899dc08127123af36a79",
|
||||
"sha256:f0b870f674851ecbfbbbd364d6b5cbdff9dcedbc7f3f5e18a6891057f21fe399"
|
||||
],
|
||||
"version": "==19.1.0"
|
||||
},
|
||||
"babel": {
|
||||
"hashes": [
|
||||
"sha256:6778d85147d5d85345c14a26aada5e478ab04e39b078b0745ee6870c2b5cf669",
|
||||
"sha256:8cba50f48c529ca3fa18cf81fa9403be176d374ac4d60738b839122dfaaa3d23"
|
||||
],
|
||||
"version": "==2.6.0"
|
||||
},
|
||||
"backports.csv": {
|
||||
"hashes": [
|
||||
"sha256:1277dfff73130b2e106bf3dd347adb3c5f6c4340882289d88f31240da92cbd6d",
|
||||
"sha256:21f6e09bab589e6c1f877edbc40277b65e626262a86e69a70137db714eaac5ce"
|
||||
],
|
||||
"version": "==1.0.7"
|
||||
},
|
||||
"backports.shutil-get-terminal-size": {
|
||||
"hashes": [
|
||||
"sha256:0975ba55054c15e346944b38956a4c9cbee9009391e41b86c68990effb8c1f64",
|
||||
"sha256:713e7a8228ae80341c70586d1cc0a8caa5207346927e23d09dcbcaf18eadec80"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.0.0"
|
||||
},
|
||||
"chardet": {
|
||||
"hashes": [
|
||||
"sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae",
|
||||
"sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691"
|
||||
],
|
||||
"version": "==3.0.4"
|
||||
},
|
||||
"coverage": {
|
||||
"hashes": [
|
||||
"sha256:01406019418aabb2d4741647cc79b0e0deb0b8c5a6f936936c303e2f82ec8e5b",
|
||||
"sha256:01a07b2b9212d4da3a1294436b58ac53f1d7aa445bda666648a5357048dc7ef3",
|
||||
"sha256:024682371464c6e3caa975aba12b4d5428f35613489340fce1334c74d590a057",
|
||||
"sha256:07c15c4a2287116a41d5966f1f5a7be765640c2e5a1917f882850a24615db6d3",
|
||||
"sha256:1d23dea598fb4d61a8577d0eb0cb2b7932db0c8d2e1394088ad5f64e3fe1febf",
|
||||
"sha256:1eeb9de833c3b976ee118a8d838af437bfa596bf60a5bf0705f4370e6d181a52",
|
||||
"sha256:229ab9c0d53c55d698b8784d53077bef7a5f1fb5d27e90dc7b6f91243b024513",
|
||||
"sha256:2f5a8bf29bdc69976d0913745daab11f8265e46ec41153f5e1e1794088019dad",
|
||||
"sha256:2f959bc1b40a3ef2c5f0c7bc282226d6d4bd585b239bcce321013afc18ff0a0f",
|
||||
"sha256:36407249a0b6669c6ad4425b0f29685579df745480c03afa70f101f09f4eead3",
|
||||
"sha256:3efa49e3da8f32071ee3d5d464cc6b6f8818524d4099b4a94b86a70b8c88d4f5",
|
||||
"sha256:422bcc6270e1c0cd9043048ce244f49072e9bd78a2c028c2ad2cfd58c79f5936",
|
||||
"sha256:4fa2b181c3bf94cfdf841148d5d9abcab1890188dd908a639bcf7a38c50092bc",
|
||||
"sha256:57c0c217270e628380f4befbbf8c5312b88ba7d81fd3d1b2218a25a2608f603c",
|
||||
"sha256:6ae76a6cd594107ad45525278e8addeae4628a59c8cde3999548d7fe1646465b",
|
||||
"sha256:6d3c762c87062a29771015f942752caef42fcc7fe4be2b03186f96788242290c",
|
||||
"sha256:8a82664931a071399d703d65af2521e2202b34f2d8db20fa22a922fec0339022",
|
||||
"sha256:8b282292973a1dc4eccfcc0776e0fde75b5b3de2e35164c2d854f7dd80149e4b",
|
||||
"sha256:9a7874ca91cee8714277cd6d1b52374809ab925bf6ae92607bf02509019caadb",
|
||||
"sha256:9c3e6551597593c1afedcbccf1371995f94457aea82cac726d1f3a25f4507386",
|
||||
"sha256:a791068e1bbe443fcd3179b1c180c27a7fc58c1554b0d10311b7659d2d2d76f5",
|
||||
"sha256:adf04843188418b012dd1974e397a7ac3faa1855cbcd69083e3af4da6de9dd81",
|
||||
"sha256:adfbbd4a1d22fd77b13ff992946b19873407e035504abe9ba537494fe013300f",
|
||||
"sha256:b25aa3531220faaf1727fc29bc000798476b4a30f429dc07898d5da48caefa15",
|
||||
"sha256:c12f34c0b50e9e8bf8c049b6c8ca59929c33cea4b1c48362c99c36838c1ee025",
|
||||
"sha256:c736faa1688222a6c8a5d8be4b66ec373ad6dab27fced8ca0d2c80fed70ac6e3",
|
||||
"sha256:ca36d83cd591d027952e5019149c4386e7058cd674bf8cb52dc622f768d689e9",
|
||||
"sha256:e1fb21a807aa0b5cc79806d8ef09078acaa83f994e15f0f7277489ca8eda51b7",
|
||||
"sha256:e53199ae110cb7e250dd5505fde34452514f4eb2f1fb7532270d2ea037454b09",
|
||||
"sha256:ea9808001dcf34d368cbef430e7885fdc76a2cf8ea96a8ed8b653797dd9555bb",
|
||||
"sha256:eaaefe0f6aa33de5a65f48dd0040d7fe08cac9ac6c35a56d0a7db109c3e733df",
|
||||
"sha256:f27772c9ee88ed3f2a784181f3d1724561499e7e448ed1706153336baa706bd5",
|
||||
"sha256:f99066d76274800145a2e658026b30962eb5079346249197e88b55c9a7855e6a",
|
||||
"sha256:fd3373ccd561b79932d12a986674e642816cfc4db4507b6a22ab30c318a85429"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.3.4"
|
||||
},
|
||||
"dealer": {
|
||||
"hashes": [
|
||||
"sha256:0a5a536fdecd9c7679534a19c59392cd21989037c14782328970a185b39e7560",
|
||||
"sha256:baaac37a4c7928545cb8b0335f48abd0ea51a0274159a9a989afb8b71f8b11c3"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.0.5"
|
||||
},
|
||||
"decorator": {
|
||||
"hashes": [
|
||||
"sha256:90022e83316363788a55352fe39cfbed357aa3a71d90e5f2803a35471de4bba8",
|
||||
"sha256:f4718552326c99544a6ec602d96b7d03ef61180cf4a492c515ecb2438dd14ccc"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.0.9"
|
||||
},
|
||||
"defusedxml": {
|
||||
"hashes": [
|
||||
"sha256:24d7f2f94f7f3cb6061acb215685e5125fbcdc40a857eff9de22518820b0a4f4",
|
||||
"sha256:702a91ade2968a82beb0db1e0766a6a273f33d4616a6ce8cde475d8e09853b20"
|
||||
],
|
||||
"version": "==0.5.0"
|
||||
},
|
||||
"diff-match-patch": {
|
||||
"hashes": [
|
||||
"sha256:a809a996d0f09b9bbd59e9bbd0b71eed8c807922512910e05cbd3f9480712ddb"
|
||||
],
|
||||
"version": "==20181111"
|
||||
},
|
||||
"django": {
|
||||
"hashes": [
|
||||
"sha256:a32c22af23634e1d11425574dce756098e015a165be02e4690179889b207c7a8",
|
||||
"sha256:d6393918da830530a9516bbbcbf7f1214c3d733738779f06b0f649f49cc698c3"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.1.5"
|
||||
},
|
||||
"django-app-namespace-template-loader": {
|
||||
"hashes": [
|
||||
"sha256:356539413b5d1de0eff91aea7a03806b5ef6874ee5420ea8c273f72bbc601d74",
|
||||
"sha256:7a450985479a2e07fe8a1e4e8208fc9e1d8b35503526dd28eba5f8ad4ba31d4e"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.4.1"
|
||||
},
|
||||
"django-auditlog": {
|
||||
"hashes": [
|
||||
"sha256:70bfc673e7023d91ab8449d745425e7a4ce5eaaf2bdcbfb9b1a2209a7af60b03"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.4.5"
|
||||
},
|
||||
"django-autocomplete-light": {
|
||||
"hashes": [
|
||||
"sha256:5ccb1c8c4b75cf72bc5dabd920190ea1ca3a340f56fb6b12d07a62202837fa75"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.2.10"
|
||||
},
|
||||
"django-bootstrap3": {
|
||||
"hashes": [
|
||||
"sha256:6f7946d513d6340bb70f25d8ec047bf3bf37bab9e499d3baca99b1aa0ec92a52"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==8.2.3"
|
||||
},
|
||||
"django-cors-headers": {
|
||||
"hashes": [
|
||||
"sha256:638aaba85f96af62557656ec559672f03d7c61769685acc405eacfaba9d4e93f",
|
||||
"sha256:c766daf9eefcb9536af9817703ea29124fffee06870f9e523b75144b4d39a694"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.0.1"
|
||||
},
|
||||
"django-filter": {
|
||||
"hashes": [
|
||||
"sha256:6f4e4bc1a11151178520567b50320e5c32f8edb552139d93ea3e30613b886f56",
|
||||
"sha256:86c3925020c27d072cdae7b828aaa5d165c2032a629abbe3c3a1be1edae61c58"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.0.0"
|
||||
},
|
||||
"django-import-export": {
|
||||
"hashes": [
|
||||
"sha256:6e748fcc647fe2a82a55136ebcbe806a45fd7fb5b1e32b33759181f1e67eeb1b",
|
||||
"sha256:7e7ebeb40702eafeb2e770914c01b9961063f472b3b395eeffbea5f39efa7257"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.7.0"
|
||||
},
|
||||
"django-jsonfield": {
|
||||
"hashes": [
|
||||
"sha256:25e53eae8bda165721773145ee0f8ae53b746bb3051b32f2821ba84d79aa77ef",
|
||||
"sha256:813c52463fbbb548fe0d85bf935d0bf72e933fae2bb00ce3ba27bf69ff6fd2ad",
|
||||
"sha256:cacf5a21e7c2490109a60f1122c05aa3858a8dc06952ad764831b4428164fc8e"
|
||||
],
|
||||
"version": "==1.1.0"
|
||||
},
|
||||
"django-modeltranslation": {
|
||||
"hashes": [
|
||||
"sha256:254ebda6caea5683407e1fb3e45ceaa2275778c6dc2db2b9d4fec3df373c2cdd"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.13b1"
|
||||
},
|
||||
"django-nocaptcha-recaptcha": {
|
||||
"hashes": [
|
||||
"sha256:d2512d5035d5f62aba5009082db28b28995a7e6f4a46713292e0f4f350f337da"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.0.19"
|
||||
},
|
||||
"django-nose": {
|
||||
"hashes": [
|
||||
"sha256:5df2df802c607daeeab8ac1e93abf54508ed6133eb93852310f512000124b4a5",
|
||||
"sha256:87663f18cb25f01d56c84ac1ff8a0e6e6a6246264b2549b751cb239d0642e76a"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.4.5"
|
||||
},
|
||||
"django-phonenumber-field": {
|
||||
"hashes": [
|
||||
"sha256:8db9d2dc833678b163adabd593cda7ad1dede81a1c18f67c895701fc44dc44f1"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.3.0"
|
||||
},
|
||||
"django-suit": {
|
||||
"hashes": [
|
||||
"sha256:19ed865a478dfca81cb5f50a70317700dd70da92c465093251d0e14330a2b92b"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.2.26"
|
||||
},
|
||||
"django-tables2": {
|
||||
"hashes": [
|
||||
"sha256:d5d3ad99580121f7ec46ea9e2420069bbd6d2f33b4fde73a376c6bf27d551146"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.6.1"
|
||||
},
|
||||
"djangorestframework": {
|
||||
"hashes": [
|
||||
"sha256:b6714c3e4b0f8d524f193c91ecf5f5450092c2145439ac2769711f7eba89a9d9",
|
||||
"sha256:c375e4f95a3a64fccac412e36fb42ba36881e52313ec021ef410b40f67cddca4"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.8.2"
|
||||
},
|
||||
"djangorestframework-jwt": {
|
||||
"hashes": [
|
||||
"sha256:5efe33032f3a4518a300dc51a51c92145ad95fb6f4b272e5aa24701db67936a7",
|
||||
"sha256:ab15dfbbe535eede8e2e53adaf52ef0cf018ee27dbfad10cbc4cbec2ab63d38c"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.11.0"
|
||||
},
|
||||
"et-xmlfile": {
|
||||
"hashes": [
|
||||
"sha256:614d9722d572f6246302c4491846d2c393c199cfa4edc9af593437691683335b"
|
||||
],
|
||||
"version": "==1.0.1"
|
||||
},
|
||||
"idna": {
|
||||
"hashes": [
|
||||
"sha256:c357b3f628cf53ae2c4c05627ecc484553142ca23264e593d327bcde5e9c3407",
|
||||
"sha256:ea8b7f6188e6fa117537c3df7da9fc686d485087abf6ac197f9c46432f7e4a3c"
|
||||
],
|
||||
"version": "==2.8"
|
||||
},
|
||||
"ipython": {
|
||||
"hashes": [
|
||||
"sha256:0480354f25b2f443e4ef1456b48f28ad1caaa6d316fca5a5eaa9ca7745ae7923",
|
||||
"sha256:98452af6450e28c9c742d567d75eb6e3a7b391ad4ce8abd5679c5f85ce7fad00",
|
||||
"sha256:d852fed59da67c7e45cb2192027da8bfd920a7856d295c247a45105968d24d5a",
|
||||
"sha256:dba42f182b5f6f26630d2202efd30383712d9f7d8d8d9896b37ae2145deca616"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.2.0"
|
||||
},
|
||||
"ipython-genutils": {
|
||||
"hashes": [
|
||||
"sha256:0c43fa84e93ad0e4dbecaffc6656ac1caf1a48359b2bb0a5da3af84164e3f49b",
|
||||
"sha256:3a0624a251a26463c9dfa0ffa635ec51c4265380980d9a50d65611c3c2bd82a6",
|
||||
"sha256:6218e9abd612fb5acfb175ea7c7b026006de4df9691d9a73c9b390cfa1a41c2b"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.1.0"
|
||||
},
|
||||
"jdcal": {
|
||||
"hashes": [
|
||||
"sha256:948fb8d079e63b4be7a69dd5f0cd618a0a57e80753de8248fd786a8a20658a07",
|
||||
"sha256:ea0a5067c5f0f50ad4c7bdc80abad3d976604f6fb026b0b3a17a9d84bb9046c9"
|
||||
],
|
||||
"version": "==1.4"
|
||||
},
|
||||
"lml": {
|
||||
"hashes": [
|
||||
"sha256:b1bef669dc077a1075fa64b99229b6341085b3b3a98d29c66df1853cc14e6c1a",
|
||||
"sha256:ea5ba817b4adc9e9f5c21725cd2475f912933b7e2dfdf0792aed80077154f63f"
|
||||
],
|
||||
"version": "==0.0.9"
|
||||
},
|
||||
"multidict": {
|
||||
"hashes": [
|
||||
"sha256:024b8129695a952ebd93373e45b5d341dbb87c17ce49637b34000093f243dd4f",
|
||||
"sha256:041e9442b11409be5e4fc8b6a97e4bcead758ab1e11768d1e69160bdde18acc3",
|
||||
"sha256:045b4dd0e5f6121e6f314d81759abd2c257db4634260abcfe0d3f7083c4908ef",
|
||||
"sha256:047c0a04e382ef8bd74b0de01407e8d8632d7d1b4db6f2561106af812a68741b",
|
||||
"sha256:068167c2d7bbeebd359665ac4fff756be5ffac9cda02375b5c5a7c4777038e73",
|
||||
"sha256:148ff60e0fffa2f5fad2eb25aae7bef23d8f3b8bdaf947a65cdbe84a978092bc",
|
||||
"sha256:1d1c77013a259971a72ddaa83b9f42c80a93ff12df6a4723be99d858fa30bee3",
|
||||
"sha256:1d48bc124a6b7a55006d97917f695effa9725d05abe8ee78fd60d6588b8344cd",
|
||||
"sha256:31dfa2fc323097f8ad7acd41aa38d7c614dd1960ac6681745b6da124093dc351",
|
||||
"sha256:34f82db7f80c49f38b032c5abb605c458bac997a6c3142e0d6c130be6fb2b941",
|
||||
"sha256:3d5dd8e5998fb4ace04789d1d008e2bb532de501218519d70bb672c4c5a2fc5d",
|
||||
"sha256:4a6ae52bd3ee41ee0f3acf4c60ceb3f44e0e3bc52ab7da1c2b2aa6703363a3d1",
|
||||
"sha256:4b02a3b2a2f01d0490dd39321c74273fed0568568ea0e7ea23e02bd1fb10a10b",
|
||||
"sha256:4b843f8e1dd6a3195679d9838eb4670222e8b8d01bc36c9894d6c3538316fa0a",
|
||||
"sha256:5de53a28f40ef3c4fd57aeab6b590c2c663de87a5af76136ced519923d3efbb3",
|
||||
"sha256:61b2b33ede821b94fa99ce0b09c9ece049c7067a33b279f343adfe35108a4ea7",
|
||||
"sha256:6a3a9b0f45fd75dc05d8e93dc21b18fc1670135ec9544d1ad4acbcf6b86781d0",
|
||||
"sha256:76ad8e4c69dadbb31bad17c16baee61c0d1a4a73bed2590b741b2e1a46d3edd0",
|
||||
"sha256:7ba19b777dc00194d1b473180d4ca89a054dd18de27d0ee2e42a103ec9b7d014",
|
||||
"sha256:7c1b7eab7a49aa96f3db1f716f0113a8a2e93c7375dd3d5d21c4941f1405c9c5",
|
||||
"sha256:7fc0eee3046041387cbace9314926aa48b681202f8897f8bff3809967a049036",
|
||||
"sha256:8ccd1c5fff1aa1427100ce188557fc31f1e0a383ad8ec42c559aabd4ff08802d",
|
||||
"sha256:8e08dd76de80539d613654915a2f5196dbccc67448df291e69a88712ea21e24a",
|
||||
"sha256:c18498c50c59263841862ea0501da9f2b3659c00db54abfbf823a80787fde8ce",
|
||||
"sha256:c49db89d602c24928e68c0d510f4fcf8989d77defd01c973d6cbe27e684833b1",
|
||||
"sha256:ce20044d0317649ddbb4e54dab3c1bcc7483c78c27d3f58ab3d0c7e6bc60d26a",
|
||||
"sha256:d1071414dd06ca2eafa90c85a079169bfeb0e5f57fd0b45d44c092546fcd6fd9",
|
||||
"sha256:d3be11ac43ab1a3e979dac80843b42226d5d3cccd3986f2e03152720a4297cd7",
|
||||
"sha256:db603a1c235d110c860d5f39988ebc8218ee028f07a7cbc056ba6424372ca31b"
|
||||
],
|
||||
"version": "==4.5.2"
|
||||
},
|
||||
"nose": {
|
||||
"hashes": [
|
||||
"sha256:9ff7c6cc443f8c51994b34a667bbcf45afd6d945be7477b52e97516fd17c53ac",
|
||||
"sha256:dadcddc0aefbf99eea214e0f1232b94f2fa9bd98fa8353711dacb112bfcbbb2a",
|
||||
"sha256:f1bffef9cbc82628f6e7d7b40d7e255aefaa1adb6a1b1d26c69a8b79e6208a98"
|
||||
],
|
||||
"version": "==1.3.7"
|
||||
},
|
||||
"nose-exclude": {
|
||||
"hashes": [
|
||||
"sha256:f78fa8b41eeb815f0486414f710f1eea0949e346cfb11d59ba6295ed69e84304"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.5.0"
|
||||
},
|
||||
"odfpy": {
|
||||
"hashes": [
|
||||
"sha256:596021f0519623ca8717331951c95e3b8d7b21e86edc7efe8cb650a0d0f59a2b"
|
||||
],
|
||||
"version": "==1.4.0"
|
||||
},
|
||||
"openpyxl": {
|
||||
"hashes": [
|
||||
"sha256:626d38647c063d55803ef4971c4d43226538d4e95cb6260c094e363ee33e10c7"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.4.11"
|
||||
},
|
||||
"pexpect": {
|
||||
"hashes": [
|
||||
"sha256:09b0a7727ce012e0fa668ef848591102d6667521655f4e72d51197c872cb9fb9",
|
||||
"sha256:c381c60f1987355b65df8f08a27f428831914c8a81091bd1778ac336fa2f27e7"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.1.0"
|
||||
},
|
||||
"phonenumberslite": {
|
||||
"hashes": [
|
||||
"sha256:2cb034b158314ca3dc034b417a64777c14b74f27f47b451270686e22eefd57d3",
|
||||
"sha256:fb9212bb8f27ec4bd5ff9a109d4309deed31b45ae5a7216bacc6644759fac82d"
|
||||
],
|
||||
"version": "==8.10.8"
|
||||
},
|
||||
"pickleshare": {
|
||||
"hashes": [
|
||||
"sha256:92ee3b0e21632542ecc9a0a245e69a126f62e5114081bdb0d32e0edd10410033",
|
||||
"sha256:b58cf7d70658a091621c0d8cc35143c8569f3827496b27ed896918c237d05d96"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.7.2"
|
||||
},
|
||||
"pillow": {
|
||||
"hashes": [
|
||||
"sha256:051de330a06c99d6f84bcf582960487835bcae3fc99365185dc2d4f65a390c0e",
|
||||
"sha256:0ae5289948c5e0a16574750021bd8be921c27d4e3527800dc9c2c1d2abc81bf7",
|
||||
"sha256:0b1efce03619cdbf8bcc61cfae81fcda59249a469f31c6735ea59badd4a6f58a",
|
||||
"sha256:163136e09bd1d6c6c6026b0a662976e86c58b932b964f255ff384ecc8c3cefa3",
|
||||
"sha256:18e912a6ccddf28defa196bd2021fe33600cbe5da1aa2f2e2c6df15f720b73d1",
|
||||
"sha256:24ec3dea52339a610d34401d2d53d0fb3c7fd08e34b20c95d2ad3973193591f1",
|
||||
"sha256:267f8e4c0a1d7e36e97c6a604f5b03ef58e2b81c1becb4fccecddcb37e063cc7",
|
||||
"sha256:3273a28734175feebbe4d0a4cde04d4ed20f620b9b506d26f44379d3c72304e1",
|
||||
"sha256:4c678e23006798fc8b6f4cef2eaad267d53ff4c1779bd1af8725cc11b72a63f3",
|
||||
"sha256:4d4bc2e6bb6861103ea4655d6b6f67af8e5336e7216e20fff3e18ffa95d7a055",
|
||||
"sha256:505738076350a337c1740a31646e1de09a164c62c07db3b996abdc0f9d2e50cf",
|
||||
"sha256:5233664eadfa342c639b9b9977190d64ad7aca4edc51a966394d7e08e7f38a9f",
|
||||
"sha256:5d95cb9f6cced2628f3e4de7e795e98b2659dfcc7176ab4a01a8b48c2c2f488f",
|
||||
"sha256:7eda4c737637af74bac4b23aa82ea6fbb19002552be85f0b89bc27e3a762d239",
|
||||
"sha256:801ddaa69659b36abf4694fed5aa9f61d1ecf2daaa6c92541bbbbb775d97b9fe",
|
||||
"sha256:825aa6d222ce2c2b90d34a0ea31914e141a85edefc07e17342f1d2fdf121c07c",
|
||||
"sha256:9c215442ff8249d41ff58700e91ef61d74f47dfd431a50253e1a1ca9436b0697",
|
||||
"sha256:a3d90022f2202bbb14da991f26ca7a30b7e4c62bf0f8bf9825603b22d7e87494",
|
||||
"sha256:a631fd36a9823638fe700d9225f9698fb59d049c942d322d4c09544dc2115356",
|
||||
"sha256:a6523a23a205be0fe664b6b8747a5c86d55da960d9586db039eec9f5c269c0e6",
|
||||
"sha256:a756ecf9f4b9b3ed49a680a649af45a8767ad038de39e6c030919c2f443eb000",
|
||||
"sha256:b117287a5bdc81f1bac891187275ec7e829e961b8032c9e5ff38b70fd036c78f",
|
||||
"sha256:ba04f57d1715ca5ff74bb7f8a818bf929a204b3b3c2c2826d1e1cc3b1c13398c",
|
||||
"sha256:cd878195166723f30865e05d87cbaf9421614501a4bd48792c5ed28f90fd36ca",
|
||||
"sha256:cee815cc62d136e96cf76771b9d3eb58e0777ec18ea50de5cfcede8a7c429aa8",
|
||||
"sha256:d1722b7aa4b40cf93ac3c80d3edd48bf93b9208241d166a14ad8e7a20ee1d4f3",
|
||||
"sha256:d7c1c06246b05529f9984435fc4fa5a545ea26606e7f450bdbe00c153f5aeaad",
|
||||
"sha256:e9c8066249c040efdda84793a2a669076f92a301ceabe69202446abb4c5c5ef9",
|
||||
"sha256:f227d7e574d050ff3996049e086e1f18c7bd2d067ef24131e50a1d3fe5831fbc",
|
||||
"sha256:fc9a12aad714af36cf3ad0275a96a733526571e52710319855628f476dcb144e"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==5.4.1"
|
||||
},
|
||||
"psycopg2-binary": {
|
||||
"hashes": [
|
||||
"sha256:036bcb198a7cc4ce0fe43344f8c2c9a8155aefa411633f426c8c6ed58a6c0426",
|
||||
"sha256:1d770fcc02cdf628aebac7404d56b28a7e9ebec8cfc0e63260bd54d6edfa16d4",
|
||||
"sha256:1fdc6f369dcf229de6c873522d54336af598b9470ccd5300e2f58ee506f5ca13",
|
||||
"sha256:21f9ddc0ff6e07f7d7b6b484eb9da2c03bc9931dd13e36796b111d631f7135a3",
|
||||
"sha256:247873cda726f7956f745a3e03158b00de79c4abea8776dc2f611d5ba368d72d",
|
||||
"sha256:3aa31c42f29f1da6f4fd41433ad15052d5ff045f2214002e027a321f79d64e2c",
|
||||
"sha256:475f694f87dbc619010b26de7d0fc575a4accf503f2200885cc21f526bffe2ad",
|
||||
"sha256:4b5e332a24bf6e2fda1f51ca2a57ae1083352293a08eeea1fa1112dc7dd542d1",
|
||||
"sha256:570d521660574aca40be7b4d532dfb6f156aad7b16b5ed62d1534f64f1ef72d8",
|
||||
"sha256:59072de7def0690dd13112d2bdb453e20570a97297070f876fbbb7cbc1c26b05",
|
||||
"sha256:5f0b658989e918ef187f8a08db0420528126f2c7da182a7b9f8bf7f85144d4e4",
|
||||
"sha256:649199c84a966917d86cdc2046e03d536763576c0b2a756059ae0b3a9656bc20",
|
||||
"sha256:6645fc9b4705ae8fbf1ef7674f416f89ae1559deec810f6dd15197dfa52893da",
|
||||
"sha256:6872dd54d4e398d781efe8fe2e2d7eafe4450d61b5c4898aced7610109a6df75",
|
||||
"sha256:6ce34fbc251fc0d691c8d131250ba6f42fd2b28ef28558d528ba8c558cb28804",
|
||||
"sha256:73920d167a0a4d1006f5f3b9a3efce6f0e5e883a99599d38206d43f27697df00",
|
||||
"sha256:8a671732b87ae423e34b51139628123bc0306c2cb85c226e71b28d3d57d7e42a",
|
||||
"sha256:8d517e8fda2efebca27c2018e14c90ed7dc3f04d7098b3da2912e62a1a5585fe",
|
||||
"sha256:9475a008eb7279e20d400c76471843c321b46acacc7ee3de0b47233a1e3fa2cf",
|
||||
"sha256:96947b8cd7b3148fb0e6549fcb31258a736595d6f2a599f8cd450e9a80a14781",
|
||||
"sha256:abf229f24daa93f67ac53e2e17c8798a71a01711eb9fcdd029abba8637164338",
|
||||
"sha256:b1ab012f276df584beb74f81acb63905762c25803ece647016613c3d6ad4e432",
|
||||
"sha256:b22b33f6f0071fe57cb4e9158f353c88d41e739a3ec0d76f7b704539e7076427",
|
||||
"sha256:b3b2d53274858e50ad2ffdd6d97ce1d014e1e530f82ec8b307edd5d4c921badf",
|
||||
"sha256:bab26a729befc7b9fab9ded1bba9c51b785188b79f8a2796ba03e7e734269e2e",
|
||||
"sha256:daa1a593629aa49f506eddc9d23dc7f89b35693b90e1fbcd4480182d1203ea90",
|
||||
"sha256:dd111280ce40e89fd17b19c1269fd1b74a30fce9d44a550840e86edb33924eb8",
|
||||
"sha256:e0b86084f1e2e78c451994410de756deba206884d6bed68d5a3d7f39ff5fea1d",
|
||||
"sha256:eb86520753560a7e89639500e2a254bb6f683342af598088cb72c73edcad21e6",
|
||||
"sha256:ff18c5c40a38d41811c23e2480615425c97ea81fd7e9118b8b899c512d97c737"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.7.6.1"
|
||||
},
|
||||
"ptyprocess": {
|
||||
"hashes": [
|
||||
"sha256:0530ce63a9295bfae7bd06edc02b6aa935619f486f0f1dc0972f516265ee81a6",
|
||||
"sha256:464cb76f7a7122743dd25507650db89cd447c51f38e4671602b3eaa2e38e05ae"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.5.1"
|
||||
},
|
||||
"pycodestyle": {
|
||||
"hashes": [
|
||||
"sha256:682256a5b318149ca0d2a9185d365d8864a768a28db66a84a2ea946bcc426766",
|
||||
"sha256:6c4245ade1edfad79c3446fadfc96b0de2759662dc29d07d80a6f27ad1ca6ba9"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.3.1"
|
||||
},
|
||||
"pyexcel": {
|
||||
"hashes": [
|
||||
"sha256:2a32accc28aea3994922606ecf7bef00ef058b56b1bea6af119ae3bb56468333",
|
||||
"sha256:f1ffe613f09285edf42132b9afc14f81adbd0f56797e5fe05e98307d00ce175f"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.5.10"
|
||||
},
|
||||
"pyexcel-io": {
|
||||
"hashes": [
|
||||
"sha256:55b2aa4ef81ba6e3285edfb1a3f3c3c69f9f4d52b6867318ae2381f88741143f",
|
||||
"sha256:de9de0d6bf9a8906c94e3b5dbe0b3a3e0a9bc893201d6a5c5b3cf84e5119d60d"
|
||||
],
|
||||
"version": "==0.5.16"
|
||||
},
|
||||
"pyexcel-xlsx": {
|
||||
"hashes": [
|
||||
"sha256:488783c3f5195bed8638f6064b11d97f706641b0f065a5416297a01db6cec5ea",
|
||||
"sha256:b3566162f7232336ebe0d40dd298145c18715009b020dddc210890cf6436ffb2"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.5.5"
|
||||
},
|
||||
"pyjwt": {
|
||||
"hashes": [
|
||||
"sha256:30b1380ff43b55441283cc2b2676b755cca45693ae3097325dea01f3d110628c",
|
||||
"sha256:4ee413b357d53fd3fb44704577afac88e72e878716116270d722723d65b42176"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.6.4"
|
||||
},
|
||||
"python-dateutil": {
|
||||
"hashes": [
|
||||
"sha256:3acbef017340600e9ff8f2994d8f7afd6eacb295383f286466a6df3961e486f0",
|
||||
"sha256:537bf2a8f8ce6f6862ad705cd68f9e405c0b5db014aa40fa29eab4335d4b1716",
|
||||
"sha256:62a2f8df3d66f878373fd0072eacf4ee52194ba302e00082828e0d263b0418d2"
|
||||
],
|
||||
"version": "==2.6.0"
|
||||
},
|
||||
"pytz": {
|
||||
"hashes": [
|
||||
"sha256:8781cdd3ca70f5a536884e051797ca213b9ff479a5c1cc57240adf37cc1eff1b",
|
||||
"sha256:be2ff04e94a2b5454ddcfbebb81ee8e46162734d4c2fcc90c422d16ab51f810b",
|
||||
"sha256:c823de61ff40d1996fe087cec343e0503881ca641b897e0f9b86c7683a0bfee1",
|
||||
"sha256:ee7c751544e35a7b7fb5e3fb25a49dade37d51e70a93e5107f10575d7102c311"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2016.4"
|
||||
},
|
||||
"pyyaml": {
|
||||
"hashes": [
|
||||
"sha256:1adecc22f88d38052fb787d959f003811ca858b799590a5eaa70e63dca50308c",
|
||||
"sha256:436bc774ecf7c103814098159fbb84c2715d25980175292c648f2da143909f95",
|
||||
"sha256:460a5a4248763f6f37ea225d19d5c205677d8d525f6a83357ca622ed541830c2",
|
||||
"sha256:5a22a9c84653debfbf198d02fe592c176ea548cccce47553f35f466e15cf2fd4",
|
||||
"sha256:7a5d3f26b89d688db27822343dfa25c599627bc92093e788956372285c6298ad",
|
||||
"sha256:9372b04a02080752d9e6f990179a4ab840227c6e2ce15b95e1278456664cf2ba",
|
||||
"sha256:a5dcbebee834eaddf3fa7366316b880ff4062e4bcc9787b78c7fbb4a26ff2dd1",
|
||||
"sha256:aee5bab92a176e7cd034e57f46e9df9a9862a71f8f37cad167c6fc74c65f5b4e",
|
||||
"sha256:c51f642898c0bacd335fc119da60baae0824f2cde95b0330b56c0553439f0673",
|
||||
"sha256:c68ea4d3ba1705da1e0d85da6684ac657912679a649e8868bd850d2c299cce13",
|
||||
"sha256:e23d0cc5299223dcc37885dae624f382297717e459ea24053709675a976a3e19"
|
||||
],
|
||||
"version": "==5.1"
|
||||
},
|
||||
"requests": {
|
||||
"hashes": [
|
||||
"sha256:545c4855cd9d7c12671444326337013766f4eea6068c3f0307fb2dc2696d580e",
|
||||
"sha256:5acf980358283faba0b897c73959cecf8b841205bb4b2ad3ef545f46eae1a133"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.11.1"
|
||||
},
|
||||
"simplegeneric": {
|
||||
"hashes": [
|
||||
"sha256:dc972e06094b9af5b855b3df4a646395e43d1c9d0d39ed345b7393560d0b9173"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==0.8.1"
|
||||
},
|
||||
"six": {
|
||||
"hashes": [
|
||||
"sha256:0ff78c403d9bccf5a425a6d31a12aa6b47f1c21ca4dc2573a7e2f32a97335eb1",
|
||||
"sha256:105f8d68616f8248e24bf0e9372ef04d3cc10104f1980f54d57b2ce73a5ad56a"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.10.0"
|
||||
},
|
||||
"tablib": {
|
||||
"hashes": [
|
||||
"sha256:0f88a9cebdaa1a2cc29ae57387082ee81015d1149ecd34e48a8c8d3b4dd21670",
|
||||
"sha256:5f33c079b07eb10cf9c4b4696add2ecf32c89db7729240546ecdcd5c92f67e13"
|
||||
],
|
||||
"version": "==0.13.0"
|
||||
},
|
||||
"telepot": {
|
||||
"hashes": [
|
||||
"sha256:8910fd6fb708e2c3ded7ca82cc945a645b717699d9f82ddff5123bb2e05f780f"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==12.3"
|
||||
},
|
||||
"texttable": {
|
||||
"hashes": [
|
||||
"sha256:2b60a5304ccfbeac80ffae7350d7c2f5d7a24e9aab5036d0f82489746419d9b2"
|
||||
],
|
||||
"version": "==1.6.1"
|
||||
},
|
||||
"traitlets": {
|
||||
"hashes": [
|
||||
"sha256:05a66843c96a320eec09df674c16ff330a43cb07f731cf2bd88aa3645a180541",
|
||||
"sha256:76eba33c89723b8fc024f950cacaf5bf2ef37999642cc9a61f4e7c1ca5cf0ac0",
|
||||
"sha256:d6db3201395f9b955786d25a1817c07291e2bcb96eb7f41683ae3836836179d7"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==4.2.1"
|
||||
},
|
||||
"urllib3": {
|
||||
"hashes": [
|
||||
"sha256:61bf29cada3fc2fbefad4fdf059ea4bd1b4a86d2b6d15e1c7c0b582b9752fe39",
|
||||
"sha256:de9529817c93f27c8ccbfead6985011db27bd0ddfcdb2d86f3f663385c6a9c22"
|
||||
],
|
||||
"version": "==1.24.1"
|
||||
},
|
||||
"xlrd": {
|
||||
"hashes": [
|
||||
"sha256:546eb36cee8db40c3eaa46c351e67ffee6eeb5fa2650b71bc4c758a29a1b29b2",
|
||||
"sha256:e551fb498759fa3a5384a94ccd4c3c02eb7c00ea424426e212ac0c57be9dfbde"
|
||||
],
|
||||
"version": "==1.2.0"
|
||||
},
|
||||
"xlwt": {
|
||||
"hashes": [
|
||||
"sha256:a082260524678ba48a297d922cc385f58278b8aa68741596a87de01a9c628b2e",
|
||||
"sha256:c59912717a9b28f1a3c2a98fd60741014b06b043936dcecbc113eaaada156c88"
|
||||
],
|
||||
"version": "==1.3.0"
|
||||
},
|
||||
"yarl": {
|
||||
"hashes": [
|
||||
"sha256:024ecdc12bc02b321bc66b41327f930d1c2c543fa9a561b39861da9388ba7aa9",
|
||||
"sha256:2f3010703295fbe1aec51023740871e64bb9664c789cba5a6bdf404e93f7568f",
|
||||
"sha256:3890ab952d508523ef4881457c4099056546593fa05e93da84c7250516e632eb",
|
||||
"sha256:3e2724eb9af5dc41648e5bb304fcf4891adc33258c6e14e2a7414ea32541e320",
|
||||
"sha256:5badb97dd0abf26623a9982cd448ff12cb39b8e4c94032ccdedf22ce01a64842",
|
||||
"sha256:73f447d11b530d860ca1e6b582f947688286ad16ca42256413083d13f260b7a0",
|
||||
"sha256:7ab825726f2940c16d92aaec7d204cfc34ac26c0040da727cf8ba87255a33829",
|
||||
"sha256:b25de84a8c20540531526dfbb0e2d2b648c13fd5dd126728c496d7c3fea33310",
|
||||
"sha256:c6e341f5a6562af74ba55205dbd56d248daf1b5748ec48a0200ba227bb9e33f4",
|
||||
"sha256:c9bb7c249c4432cd47e75af3864bc02d26c9594f49c82e2a28624417f0ae63b8",
|
||||
"sha256:e060906c0c585565c718d1c3841747b61c5439af2211e185f6739a9412dfbde1"
|
||||
],
|
||||
"version": "==1.3.0"
|
||||
}
|
||||
},
|
||||
"develop": {
|
||||
"autopep8": {
|
||||
"hashes": [
|
||||
"sha256:33d2b5325b7e1afb4240814fe982eea3a92ebea712869bfd08b3c0393404248c"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==1.4.3"
|
||||
},
|
||||
"entrypoints": {
|
||||
"hashes": [
|
||||
"sha256:589f874b313739ad35be6e0cd7efde2a4e9b6fea91edcc34e58ecbb8dbe56d19",
|
||||
"sha256:c70dd71abe5a8c85e55e12c19bd91ccfeec11a6e99044204511f9ed547d48451"
|
||||
],
|
||||
"version": "==0.3"
|
||||
},
|
||||
"flake8": {
|
||||
"hashes": [
|
||||
"sha256:859996073f341f2670741b51ec1e67a01da142831aa1fdc6242dbf88dffbe661",
|
||||
"sha256:a796a115208f5c03b18f332f7c11729812c8c3ded6c46319c59b53efd3819da8"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==3.7.7"
|
||||
},
|
||||
"mccabe": {
|
||||
"hashes": [
|
||||
"sha256:ab8a6258860da4b6677da4bd2fe5dc2c659cff31b3ee4f7f5d64e79735b80d42",
|
||||
"sha256:dd8d182285a0fe56bace7f45b5e7d1a6ebcbf524e8f3bd87eb0f125271b8831f"
|
||||
],
|
||||
"version": "==0.6.1"
|
||||
},
|
||||
"pycodestyle": {
|
||||
"hashes": [
|
||||
"sha256:682256a5b318149ca0d2a9185d365d8864a768a28db66a84a2ea946bcc426766",
|
||||
"sha256:6c4245ade1edfad79c3446fadfc96b0de2759662dc29d07d80a6f27ad1ca6ba9"
|
||||
],
|
||||
"index": "pypi",
|
||||
"version": "==2.3.1"
|
||||
},
|
||||
"pyflakes": {
|
||||
"hashes": [
|
||||
"sha256:17dbeb2e3f4d772725c777fabc446d5634d1038f234e77343108ce445ea69ce0",
|
||||
"sha256:d976835886f8c5b31d47970ed689944a0262b5f3afa00a5a7b4dc81e5449f8a2"
|
||||
],
|
||||
"version": "==2.1.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,7 @@ body {
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: bottom center;
|
||||
background-image: url("/static/img/smokes.png");
|
||||
background-image: url("/static/coffee_scale/img/smokes.png");
|
||||
transform-origin: bottom;
|
||||
animation: smokes 8s ease-in-out 0s infinite;
|
||||
opacity:0;
|
||||
@@ -27,7 +27,7 @@ body {
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: top center;
|
||||
background-image: url("/static/img/coffeecup3.png");
|
||||
background-image: url("/static/coffee_scale/img/coffeecup3.png");
|
||||
height:60%;
|
||||
}
|
||||
#scale{
|
||||
|
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 9.0 KiB |
@@ -1,3 +1,6 @@
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Coffee Cups @Guild Room - AYY SIK ry</title>
|
||||
@@ -12,8 +15,8 @@
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/paho-mqtt/1.0.2/mqttws31.js"
|
||||
type="text/javascript"></script>
|
||||
<link rel="stylesheet" href="/static/css/coffee.css" />
|
||||
<script src="/static/js/coffee.js"></script>
|
||||
<link rel="stylesheet" href="{% static "coffee_scale/css/coffee.css" %}">
|
||||
<script src="{% static "coffee_scale/js/coffee.js" %}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
from django.conf.urls import url
|
||||
from django.views.generic.base import RedirectView
|
||||
|
||||
from django.conf import settings
|
||||
from .views import coffee_view
|
||||
|
||||
favicon_view = RedirectView.as_view(url='static/img/favicon.ico', permanent=True)
|
||||
|
||||
urlpatterns = [
|
||||
|
||||
# landing page
|
||||
url(r'^$', coffee_view),
|
||||
]
|
||||
|
||||
if settings.DEBUG:
|
||||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||
urlpatterns += staticfiles_urlpatterns()
|
||||
|
||||
@@ -8,4 +8,4 @@ from django.conf import settings
|
||||
|
||||
|
||||
def coffee_view(request):
|
||||
return render(request, 'coffee.html')
|
||||
return render(request, 'coffee_scale:coffee.html')
|
||||
|
||||
@@ -5,9 +5,9 @@ services:
|
||||
image: postgres
|
||||
web:
|
||||
build: .
|
||||
image: git.sahkoinsinoorikilta.fi:4567/vtmk/web2.0
|
||||
command: ["bash", "-c", "cd /code && ./wait-for-it.sh db:5432 -- bash setup.sh --no-input --no-npm && python manage.py runserver 0.0.0.0:8080"]
|
||||
image: registry.gitlab.com/sahkoinsinoorikilta/vtmk/web2.0-backend
|
||||
command: ["bash", "-c", "cd /code && ./wait-for-it.sh db:5432 -- bash setup.sh --no-input --no-npm && python manage.py runserver 0.0.0.0:8000"]
|
||||
ports:
|
||||
- "8080:8080"
|
||||
- "8000:8000"
|
||||
depends_on:
|
||||
- db
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class ExpensesClaimConfig(AppConfig):
|
||||
name = 'expenses_claim'
|
||||
@@ -0,0 +1,32 @@
|
||||
"""Expenses claim form."""
|
||||
|
||||
from django import forms
|
||||
from string import ascii_uppercase
|
||||
|
||||
|
||||
class ExpensesClaim(forms.Form):
|
||||
"""Expenses claim form."""
|
||||
|
||||
name = forms.CharField(label='Nimi', max_length=100)
|
||||
iban = forms.CharField(label='IBAN', max_length=100)
|
||||
email = forms.EmailField(label='Sähköposti', max_length=100)
|
||||
amount = forms.DecimalField(label='Yhteensä', decimal_places=2)
|
||||
|
||||
def clean_iban(self):
|
||||
"""Validate IBAN."""
|
||||
orig_iban = self.cleaned_data['iban']
|
||||
# Remove spaces.
|
||||
cleaned_iban = orig_iban.replace(' ', '')
|
||||
# Move first 4 symbols to the end of the string.
|
||||
cleaned_iban = cleaned_iban[4:] + cleaned_iban[0:4]
|
||||
LETTERS = {letter: str(index) for index,
|
||||
letter in enumerate(ascii_uppercase, start=10)}
|
||||
cleaned_iban = cleaned_iban.upper()
|
||||
# Replace all letters with numbers, so that A=10, B=11, ..., Z=35.
|
||||
cleaned_iban = [LETTERS[char] if char in LETTERS
|
||||
else char for char in cleaned_iban]
|
||||
cleaned_iban = ''.join(cleaned_iban)
|
||||
# If cleaned_iban modulo 97 != 1 the IBAN number is invalid.
|
||||
if int(cleaned_iban) % 97 != 1:
|
||||
raise forms.ValidationError('Invalid IBAN number!')
|
||||
return orig_iban
|
||||
@@ -0,0 +1,3 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
@@ -0,0 +1,169 @@
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.heading {
|
||||
padding: 20px 10px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.claim-form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
width: 100%
|
||||
}
|
||||
|
||||
.form {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
padding: 10px 20px;
|
||||
width: 60%;
|
||||
}
|
||||
|
||||
.table {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: space-between;
|
||||
padding: 20px 10px;
|
||||
}
|
||||
|
||||
.scrollarea {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
.tablerow {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: space-between;
|
||||
flex-wrap: wrap;
|
||||
padding: 10px 5px;
|
||||
}
|
||||
|
||||
.fieldscolumn {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: flex-start;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.fieldsrow {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: center;
|
||||
align-items: stretch;
|
||||
padding: 5px 10px;
|
||||
}
|
||||
|
||||
.submit {
|
||||
align-self: center;
|
||||
width: 30%;
|
||||
margin: 20px 10px;
|
||||
}
|
||||
|
||||
.imageupload > input {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.fieldsrow > div {
|
||||
margin: 10px 20px;
|
||||
}
|
||||
|
||||
.fieldscolumn > div {
|
||||
margin: 10px 20px;
|
||||
}
|
||||
|
||||
|
||||
.fieldscolumn > div > label {
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.money > input {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
#addreceipt {
|
||||
height: 40px;
|
||||
}
|
||||
|
||||
#total {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: flex-end;
|
||||
padding: 20px 10px;
|
||||
}
|
||||
|
||||
#receiptslist {
|
||||
height: 20rem;
|
||||
}
|
||||
|
||||
#info2 {
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
#textbox > textarea {
|
||||
align-self: flex-end;
|
||||
}
|
||||
|
||||
#id_iban {
|
||||
width: 18rem;
|
||||
}
|
||||
|
||||
|
||||
.fieldscolumn > #textbox > textarea {
|
||||
height: 8rem;
|
||||
width: 18rem;
|
||||
}
|
||||
|
||||
|
||||
@media only screen and (max-width: 768px) {
|
||||
.heading {
|
||||
font-size: 18px;
|
||||
padding: 5px 5px;
|
||||
}
|
||||
|
||||
h1.heading {
|
||||
visibility: hidden;
|
||||
height: 0px;
|
||||
}
|
||||
|
||||
.table {
|
||||
padding: 5px 5px
|
||||
}
|
||||
|
||||
#total {
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.fieldsrow {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-around;
|
||||
padding: 5px 5px
|
||||
}
|
||||
|
||||
#receiptslist {
|
||||
width: 12rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-height: 741px) {
|
||||
#receiptslist {
|
||||
height: 17rem;
|
||||
}
|
||||
}
|
||||
|
||||
@media only screen and (max-height: 569px) {
|
||||
#receiptslist {
|
||||
height: 10rem;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
function addReceipt(event) {
|
||||
event.preventDefault();
|
||||
var receipts = document.getElementById("receiptslist");
|
||||
var div2append = document.createElement("div");
|
||||
var newrow = receipts.appendChild(div2append);
|
||||
newrow.classList.add("tablerow");
|
||||
|
||||
div2append = document.createElement("div");
|
||||
var div1 = newrow.appendChild(div2append);
|
||||
div1.classList.add("imageupload");
|
||||
div2append = document.createElement("div");
|
||||
var div2 = newrow.appendChild(div2append);
|
||||
div2.classList.add("desc");
|
||||
div2append = document.createElement("div");
|
||||
var div3 = newrow.appendChild(div2append);
|
||||
div3.classList.add("money");
|
||||
|
||||
var file = document.getElementById("newreceipt");
|
||||
var desc = document.getElementById("adddescription");
|
||||
var sum = document.getElementById("addsum");
|
||||
div1.appendChild(file.cloneNode(true));
|
||||
div2.appendChild(document.createTextNode(desc.value));
|
||||
div3.appendChild(document.createTextNode(sum.value));
|
||||
|
||||
var total = document.getElementById("totalsum");
|
||||
total.value = Number(total.value) + Number(sum.value);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
{% extends "project.html" %}
|
||||
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
{% block styles %}
|
||||
<script src="{% static "claim_form/js/addReceipt.js" %}"></script>
|
||||
<link rel="stylesheet" href="{% static "claim_form/css/base.css" %}"></script>
|
||||
{% endblock styles %}
|
||||
|
||||
{% block body %}
|
||||
|
||||
<div class="claim-form">
|
||||
{% block content %}
|
||||
{% include "expenses_claim:form.html" %}
|
||||
{% endblock %}
|
||||
</div>
|
||||
|
||||
{% endblock body %}
|
||||
@@ -0,0 +1,20 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<title>Raha-anomus</title>
|
||||
</head>
|
||||
<body>
|
||||
<h1>Raha-anomus</h1>
|
||||
<div>
|
||||
<div>
|
||||
{{ name }}
|
||||
</div>
|
||||
<div>
|
||||
{{ iban }}
|
||||
</div>
|
||||
<div>
|
||||
{{ amount }}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,72 @@
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% block content %}
|
||||
|
||||
<form class="form" id="claim" action="" method="post">
|
||||
<h1 class="heading">Aalto Yliopiston Sähköinsinöörikilta ry Raha-anomuslomake</h1>
|
||||
<div class="fieldsrow">
|
||||
<div class="imageupload" id="newreceipt">
|
||||
<label for="newreceipt">
|
||||
Kuitti
|
||||
<img class="thumbnail" src="{% static "claim_form/img/icon.png" %}"/>
|
||||
</label>
|
||||
<input id="selectreceipt" type="file"/>
|
||||
</div>
|
||||
<div>
|
||||
<label for="adddescription">
|
||||
Kuvaus
|
||||
</label>
|
||||
<input id="adddescription" type="text">
|
||||
</div>
|
||||
<div class="money">
|
||||
<label for="addsum">
|
||||
Summa
|
||||
</label>
|
||||
<input type="number" id="addsum" maxlength=100/>
|
||||
</div>
|
||||
<div>
|
||||
<button id="addreceipt" onclick="addReceipt(event)">Lisää kuitti</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="table">
|
||||
<div class="scrollarea" id="receiptslist">
|
||||
<div class="tablerow">
|
||||
<div class="tableelement">Kuitti</div>
|
||||
<div class="tableelement">Kuvaus</div>
|
||||
<div class="tableelement">Summa</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="money" id="total">
|
||||
<label for="id_amount">Yhteensä</label>
|
||||
{{ form.amount }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="fieldscolumn">
|
||||
<div class="fieldsrow">
|
||||
<div class="fieldscolumn" id="info1">
|
||||
<div id="textbox">
|
||||
<label for="selite">Selite</label>
|
||||
<textarea id="selite"></textarea>
|
||||
</div>
|
||||
<div>
|
||||
<label for="id_iban">{{ form.iban.label }}</label>
|
||||
{{ form.iban }}
|
||||
</div>
|
||||
</div>
|
||||
<div class="fieldscolumn" id="info2">
|
||||
<div>
|
||||
<label for="id_name">{{ form.name.label }}</label>
|
||||
{{ form.name }}
|
||||
</div>
|
||||
<div>
|
||||
<label for="id_email">{{ form.email.label }}</label>
|
||||
{{ form.email }}
|
||||
</div>
|
||||
<input class="submit" id="submitclaim" type="submit" value="Submit"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{% csrf_token %}
|
||||
</form>
|
||||
|
||||
{% endblock content %}
|
||||
@@ -0,0 +1,60 @@
|
||||
from django.test import TestCase
|
||||
from .forms import ExpensesClaim
|
||||
|
||||
|
||||
class ExpensesClaimTest(TestCase):
|
||||
"""Test expenses claim form."""
|
||||
|
||||
def test_valid_data1(self):
|
||||
form = ExpensesClaim({
|
||||
'name': "John Doe",
|
||||
'email': 'john@doe.com',
|
||||
'iban': "FI37 1590 3000 0007 76",
|
||||
'amount': 12.54
|
||||
})
|
||||
self.assertTrue(form.is_valid())
|
||||
|
||||
def test_valid_data2(self):
|
||||
form = ExpensesClaim({
|
||||
'name': "John Cena",
|
||||
'email': 'john@cena.com',
|
||||
'iban': "AL35202111090000000001234567",
|
||||
'amount': 12
|
||||
})
|
||||
self.assertTrue(form.is_valid())
|
||||
|
||||
def test_valid_data3(self):
|
||||
form = ExpensesClaim({
|
||||
'name': "John Wayne",
|
||||
'email': 'john@wayne.com',
|
||||
'iban': "BR1500000000000010932840814P2",
|
||||
'amount': 12.0
|
||||
})
|
||||
self.assertTrue(form.is_valid())
|
||||
|
||||
def test_invalid_iban(self):
|
||||
form = ExpensesClaim({
|
||||
'name': "John Lennon",
|
||||
'email': 'john@lennon.com',
|
||||
'iban': "FI3734 1590 3000 0007 76",
|
||||
'amount': 12.54
|
||||
})
|
||||
self.assertFalse(form.is_valid())
|
||||
|
||||
def test_invalid_amount(self):
|
||||
form = ExpensesClaim({
|
||||
'name': "John Kenedy",
|
||||
'email': 'john@kenedy.com',
|
||||
'iban': "FI37 1590 3000 0007 76",
|
||||
'amount': "asd"
|
||||
})
|
||||
self.assertFalse(form.is_valid())
|
||||
|
||||
def test_invalid_amount_decimal_places(self):
|
||||
form = ExpensesClaim({
|
||||
'name': "John Travolta",
|
||||
'email': 'john@travolta.com',
|
||||
'iban': "FI37 1590 3000 0007 76",
|
||||
'amount': 12.544
|
||||
})
|
||||
self.assertFalse(form.is_valid())
|
||||
@@ -0,0 +1,9 @@
|
||||
"""Expenses claim urls."""
|
||||
|
||||
from django.conf.urls import url
|
||||
from .views import claim
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
url(r'^new', claim)
|
||||
]
|
||||
@@ -0,0 +1,41 @@
|
||||
"""Expenses claim views."""
|
||||
|
||||
from django.shortcuts import render
|
||||
from django.views.decorators.http import require_http_methods
|
||||
from django.http import HttpResponse
|
||||
from webapp.utils import send_email_with_attachment
|
||||
from django.template.loader import render_to_string
|
||||
from weasyprint import HTML
|
||||
from .forms import ExpensesClaim
|
||||
|
||||
|
||||
@require_http_methods(["GET", "POST"])
|
||||
def claim(request):
|
||||
"""Render expenses claim form."""
|
||||
|
||||
if request.method == 'POST':
|
||||
form = ExpensesClaim(request.POST)
|
||||
if form.is_valid():
|
||||
name = form.cleaned_data['name']
|
||||
amount = form.cleaned_data['amount']
|
||||
iban = form.cleaned_data['iban']
|
||||
html_string = render_to_string('expenses_claim:claim2pdf.html',
|
||||
{'name': name, 'iban': iban,
|
||||
'amount': amount}).encode('UTF-8')
|
||||
html = HTML(string=html_string)
|
||||
attachment = html.write_pdf()
|
||||
response = HttpResponse(
|
||||
attachment, content_type='application/pdf;'
|
||||
)
|
||||
response['Content-Disposition'] = 'filename=claim.pdf'
|
||||
|
||||
email = "leo.kivikunnas@aalto.fi"
|
||||
subject = "Test expenses claim"
|
||||
body = "Test"
|
||||
send_email_with_attachment(email, subject, body, attachment)
|
||||
return response
|
||||
|
||||
elif request.method == 'GET':
|
||||
form = ExpensesClaim()
|
||||
|
||||
return render(request, 'expenses_claim:base.html', {'form': form})
|
||||
@@ -1,45 +0,0 @@
|
||||
# Ilmotunkki
|
||||
|
||||
## Terms
|
||||
- Signup, Form with collection of questions
|
||||
- Response, One answer to some signup
|
||||
- Quota, Amount of people allowed to respond with some option selected.
|
||||
- In generic case there is no option and quota is just max number of people.
|
||||
|
||||
## Requirements
|
||||
|
||||
- Officials may generate signups forms
|
||||
- Officials may see results from signups
|
||||
- Officials may see some stats from their signups
|
||||
- for example distributions of multiple choice answers
|
||||
- Officials should be able to edit signups wherever possible
|
||||
- Propably not possible to edit after first response
|
||||
- Officials should be able to delete responses
|
||||
- Officials should be able to embed payment information to the signup?
|
||||
- TODO: is there need for unique reference numbers for every response?
|
||||
- Officials should be able to save a signup to a reusable template.
|
||||
|
||||
- Signup may be attached to an event
|
||||
- multiple signups to a single event?
|
||||
|
||||
- Signup should support custom quotas
|
||||
- Atleast quotas from multiple choices and checkboxes
|
||||
- Text quotas are risky (typos everywhere!!)
|
||||
- Signup should have start and end times
|
||||
- signup should support atleast following questiontypes
|
||||
- Text
|
||||
- multiple choice (select one)
|
||||
- checkbox (boolean yes/no)
|
||||
|
||||
- Signup should support reserve slots.
|
||||
TODO: quota based reserves or generic? or both?
|
||||
|
||||
- Responding should send confirm email
|
||||
- Response should be editable by responder and only by the responder until the closing of the signup
|
||||
- TODO: is there need to custom edit period or disable?
|
||||
|
||||
- Responders should see amount of quotas left.
|
||||
- Responders should see some information about other responses
|
||||
- TODO: names? should this be editable by officials?
|
||||
- NOTE: Quota related info is exposed if any info is printed
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
from django.apps import AppConfig
|
||||
|
||||
|
||||
class IlmotunkkiConfig(AppConfig):
|
||||
name = 'ilmotunkki'
|
||||
@@ -1,16 +0,0 @@
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
|
||||
|
||||
class Signup(models.Model):
|
||||
start = models.DateTimeField()
|
||||
end = models.DateTimeField()
|
||||
|
||||
|
||||
class Question(models.Model):
|
||||
pass
|
||||
|
||||
|
||||
class Answer(models.Model):
|
||||
signup = models.ForeignKey(Signup, on_delete=models.CASCADE)
|
||||
question = models.ForeignKey(Question, on_delete=models.PROTECT)
|
||||
@@ -1,3 +0,0 @@
|
||||
from django.shortcuts import render
|
||||
|
||||
# Create your views here.
|
||||
@@ -1,10 +1,9 @@
|
||||
"""Admin site registers."""
|
||||
|
||||
from django.contrib import admin
|
||||
from infoscreen.models import Rotation, InfoItem, InfoInstance
|
||||
from infoscreen.models import ImageInfoItem, ExternalImageInfoItem, ABBInfoItem
|
||||
from infoscreen.models import ExternalWebsiteInfoItem
|
||||
from infoscreen.models import VideoInfoItem
|
||||
from infoscreen.models import (
|
||||
Rotation, InfoItem, InfoInstance, ImageInfoItem,
|
||||
ExternalImageInfoItem, ABBInfoItem, ExternalWebsiteInfoItem, VideoInfoItem)
|
||||
|
||||
# Register your models here.
|
||||
admin.site.register(Rotation)
|
||||
|
||||
@@ -1,70 +0,0 @@
|
||||
"""File containing Infoscreen HSL data fetcher classes."""
|
||||
|
||||
import requests
|
||||
import json
|
||||
import logging
|
||||
import os
|
||||
import pytz
|
||||
|
||||
from datetime import timedelta, datetime
|
||||
from django.utils import timezone, dateparse
|
||||
from django.utils.dateformat import format
|
||||
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
with open(os.path.join(settings.BASE_DIR, 'infoscreen', 'hsl_stops.graphql')) as stops_file:
|
||||
STOPS_QUERY = stops_file.read()
|
||||
|
||||
with open(os.path.join(settings.BASE_DIR, 'infoscreen', 'hsl_stops_variables.json')) as vars_file:
|
||||
STOPS_VARS = json.loads(vars_file.read())
|
||||
|
||||
API_URL = 'https://api.digitransit.fi/routing/v1/routers/hsl/index/graphql'
|
||||
API_HEADERS = {'Content-Type': 'application/json'}
|
||||
|
||||
|
||||
def fetch():
|
||||
"""Fetch data from HSL API."""
|
||||
|
||||
query_vars = STOPS_VARS.copy()
|
||||
query_vars['startTime_6'] = format(timezone.now(), 'U')
|
||||
|
||||
post_data = json.dumps({
|
||||
'operationName': 'NearestRoutesContainer',
|
||||
'query': STOPS_QUERY,
|
||||
'variables': query_vars,
|
||||
})
|
||||
|
||||
resp = requests.post(API_URL, data=post_data, headers=API_HEADERS)
|
||||
|
||||
data = resp.json()
|
||||
|
||||
items = data['data']['viewer']['_nearest']['edges']
|
||||
places = map(lambda item: item['node']['place'], items)
|
||||
|
||||
schedule = []
|
||||
for place in places:
|
||||
route = place['pattern']['route']['shortName']
|
||||
stop_times = place['_stoptimes']
|
||||
for stop_time in stop_times:
|
||||
timestamp = time_utc = stop_time['serviceDay'] + stop_time['realtimeArrival']
|
||||
headsign = stop_time['stopHeadsign']
|
||||
stop_name = stop_time['stop']['name']
|
||||
time_diff = (timestamp - timezone.now().timestamp()) / 60 # minutes
|
||||
|
||||
if time_diff < settings.HSL_DEPARTURE_THRESHOLD:
|
||||
continue
|
||||
elif time_diff < settings.HSL_HURRY_THRESHOLD:
|
||||
time = '{} min'.format(int(time_diff))
|
||||
else:
|
||||
time = pytz.utc.localize(datetime.fromtimestamp(timestamp)).strftime('%H:%M')
|
||||
|
||||
schedule.append({
|
||||
'route': route,
|
||||
'headsign': headsign,
|
||||
'timestamp': time,
|
||||
'stop': stop_name,
|
||||
'utc': time_utc,
|
||||
})
|
||||
|
||||
return schedule
|
||||
@@ -1,71 +0,0 @@
|
||||
query NearestRoutesContainer($lat_0: Float!, $lon_1: Float!, $maxDistance_2: Int!, $maxResults_3: Int!, $timeRange_7: Int!, $numberOfDepartures_8: Int!, $filterByModes_4: [Mode]!, $filterByPlaceTypes_5: [FilterPlaceType]!, $startTime_6: Long!) {
|
||||
viewer {
|
||||
...F5
|
||||
}
|
||||
}
|
||||
|
||||
fragment F0 on DepartureRow {
|
||||
_stoptimes4caEfh: stoptimes(startTime: $startTime_6, timeRange: $timeRange_7, numberOfDepartures: $numberOfDepartures_8) {
|
||||
pickupType
|
||||
serviceDay
|
||||
realtimeDeparture
|
||||
}
|
||||
id
|
||||
}
|
||||
|
||||
fragment F1 on DepartureRow {
|
||||
pattern {
|
||||
route {
|
||||
shortName
|
||||
}
|
||||
}
|
||||
_stoptimes: stoptimes(startTime: $startTime_6, timeRange: $timeRange_7, numberOfDepartures: $numberOfDepartures_8) {
|
||||
realtimeArrival
|
||||
serviceDay
|
||||
stopHeadsign
|
||||
stop {
|
||||
name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fragment F2 on BikeRentalStation {
|
||||
id
|
||||
}
|
||||
|
||||
fragment F3 on placeAtDistance {
|
||||
distance
|
||||
place {
|
||||
id
|
||||
__typename
|
||||
...F1
|
||||
...F2
|
||||
}
|
||||
id
|
||||
}
|
||||
|
||||
fragment F4 on placeAtDistanceConnection {
|
||||
edges {
|
||||
node {
|
||||
distance
|
||||
place {
|
||||
id
|
||||
__typename
|
||||
...F0
|
||||
}
|
||||
id
|
||||
...F3
|
||||
}
|
||||
cursor
|
||||
}
|
||||
pageInfo {
|
||||
hasNextPage
|
||||
hasPreviousPage
|
||||
}
|
||||
}
|
||||
|
||||
fragment F5 on QueryType {
|
||||
_nearest: nearest(lat: $lat_0, lon: $lon_1, maxDistance: $maxDistance_2, maxResults: $maxResults_3, first: $maxResults_3, filterByModes: $filterByModes_4, filterByPlaceTypes: $filterByPlaceTypes_5) {
|
||||
...F4
|
||||
}
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
{
|
||||
"lat_0": 60.190480099999995,
|
||||
"lon_1": 24.8275665,
|
||||
"maxDistance_2": 1000,
|
||||
"maxResults_3": 50,
|
||||
"numberOfDepartures_8": 2,
|
||||
"timeRange_7": 7200,
|
||||
"filterByModes_4": ["BUS"],
|
||||
"filterByPlaceTypes_5": ["DEPARTURE_ROW"]
|
||||
}
|
||||
@@ -1,10 +0,0 @@
|
||||
from django.core.management.base import BaseCommand
|
||||
from infoscreen.hsl_fetcher import HSLFetcher
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
help = 'Loads HSL timetables and save to json file.'
|
||||
|
||||
def handle(self, *args, **options):
|
||||
fetcher = HSLFetcher()
|
||||
fetcher.fetch()
|
||||
@@ -15,4 +15,7 @@ class Migration(migrations.Migration):
|
||||
migrations.DeleteModel(
|
||||
name='HSLDataModel',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='HslInfoItem',
|
||||
),
|
||||
]
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
# Generated by Django 2.1.5 on 2019-03-26 12:49
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('infoscreen', '0006_delete_hsldatamodel'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='LunchItem',
|
||||
fields=[
|
||||
('infoitem_ptr', models.OneToOneField(auto_created=True, on_delete=django.db.models.deletion.CASCADE, parent_link=True, primary_key=True, serialize=False, to='infoscreen.InfoItem')),
|
||||
],
|
||||
bases=('infoscreen.infoitem',),
|
||||
),
|
||||
]
|
||||
@@ -98,12 +98,12 @@ class ABBInfoItem(InfoItem):
|
||||
|
||||
def get_template_url(self):
|
||||
"""Return ABB infoitem template url."""
|
||||
return "/static/html/abb.html"
|
||||
return "/static/infoscreen/html/abb.html"
|
||||
|
||||
@staticmethod
|
||||
def get_create_template_url():
|
||||
"""Call create ABB infoitem template url command."""
|
||||
return "/static/html/abb_create.html"
|
||||
return "/static/infoscreen/html/abb_create.html"
|
||||
|
||||
|
||||
class ApyInfoItem(InfoItem):
|
||||
@@ -113,12 +113,12 @@ class ApyInfoItem(InfoItem):
|
||||
|
||||
def get_template_url(self):
|
||||
"""Return APY infoitem template url."""
|
||||
return "/static/html/apy.html"
|
||||
return "/static/infoscreen/html/apy.html"
|
||||
|
||||
@staticmethod
|
||||
def get_create_template_url():
|
||||
"""Call create APY infoitem template url command."""
|
||||
return "/static/html/apy_create.html"
|
||||
return "/static/infoscreen/html/apy_create.html"
|
||||
|
||||
|
||||
class ExternalWebsiteInfoItem(InfoItem):
|
||||
@@ -129,12 +129,12 @@ class ExternalWebsiteInfoItem(InfoItem):
|
||||
|
||||
def get_template_url(self):
|
||||
"""Return external website infoitem template url."""
|
||||
return "/static/html/external_website.html?url={}".format(self.name)
|
||||
return "/static/infoscreen/html/external_website.html?url={}".format(self.name)
|
||||
|
||||
@staticmethod
|
||||
def get_create_template_url():
|
||||
"""Call create external website infoitem template url command."""
|
||||
return "/static/html/external_website_create.html"
|
||||
return "/static/infoscreen/html/external_website_create.html"
|
||||
|
||||
def get_dict(self):
|
||||
"""Convert django model to dict and return it."""
|
||||
@@ -185,12 +185,25 @@ class SossoInfoItem(InfoItem):
|
||||
|
||||
def get_template_url(self):
|
||||
"""Return Sosso infoitem template url."""
|
||||
return "/static/html/sosso.html"
|
||||
return "/static/infoscreen/html/sosso.html"
|
||||
|
||||
@staticmethod
|
||||
def get_create_template_url():
|
||||
"""Call create Sosso infoitem template url command."""
|
||||
return "/static/html/sosso_create.html"
|
||||
return "/static/infoscreen/html/sosso_create.html"
|
||||
|
||||
|
||||
class LunchItem(InfoItem):
|
||||
"""Class for Lunch Infoscreen item."""
|
||||
|
||||
display_name = _("Today's lunch")
|
||||
|
||||
def get_template_url(self):
|
||||
return "/static/infoscreen/html/lunch.html"
|
||||
|
||||
@staticmethod
|
||||
def get_create_template_url():
|
||||
return "/static/infoscreen/html/lunch_create.html"
|
||||
|
||||
|
||||
class EventInfoItem(InfoItem):
|
||||
@@ -200,12 +213,12 @@ class EventInfoItem(InfoItem):
|
||||
|
||||
def get_template_url(self):
|
||||
"""Return Event infoitem template url."""
|
||||
return "/static/html/events.html"
|
||||
return "/static/infoscreen/html/events.html"
|
||||
|
||||
@staticmethod
|
||||
def get_create_template_url():
|
||||
"""Call create Event infoitem template url command."""
|
||||
return "/static/html/events_create.html"
|
||||
return "/static/infoscreen/html/events_create.html"
|
||||
|
||||
|
||||
class ImageInfoItem(InfoItem):
|
||||
@@ -218,12 +231,12 @@ class ImageInfoItem(InfoItem):
|
||||
"""Return Image infoitem template url."""
|
||||
# get param to avoid angular from optimizing same template
|
||||
# with different options
|
||||
return "/static/html/generic_image.html?img={}".format(self.name)
|
||||
return "/static/infoscreen/html/generic_image.html?img={}".format(self.name)
|
||||
|
||||
@staticmethod
|
||||
def get_create_template_url():
|
||||
"""Call create Image infoitem template url command."""
|
||||
return "/static/html/generic_image_create.html"
|
||||
return "/static/infoscreen/html/generic_image_create.html"
|
||||
|
||||
def get_dict(self):
|
||||
"""Convert django model to dict and return it."""
|
||||
@@ -240,12 +253,12 @@ class VideoInfoItem(InfoItem):
|
||||
|
||||
def get_template_url(self):
|
||||
"""Return Video infoitem template url."""
|
||||
return "/static/html/generic_video.html?video={}".format(self.name)
|
||||
return "/static/infoscreen/html/generic_video.html?video={}".format(self.name)
|
||||
|
||||
@staticmethod
|
||||
def get_create_template_url():
|
||||
"""Call create Video infoitem template url command."""
|
||||
return "/static/html/generic_video_create.html"
|
||||
return "/static/infoscreen/html/generic_video_create.html"
|
||||
|
||||
def get_dict(self):
|
||||
"""Convert django model to dict and return it."""
|
||||
@@ -254,21 +267,6 @@ class VideoInfoItem(InfoItem):
|
||||
return d
|
||||
|
||||
|
||||
class HslInfoItem(InfoItem):
|
||||
"""Class for HSL Infoscreen item."""
|
||||
|
||||
display_name = _("HSL timetables")
|
||||
|
||||
def get_template_url(self):
|
||||
"""Return HSL infoitem template url."""
|
||||
return "/static/html/hsl.html"
|
||||
|
||||
@staticmethod
|
||||
def get_create_template_url():
|
||||
"""Call create HSL infoitem template url command."""
|
||||
return "/static/html/hsl_create.html"
|
||||
|
||||
|
||||
class ExternalImageInfoItem(InfoItem):
|
||||
"""Class for External Image Infoscreen item."""
|
||||
|
||||
@@ -277,12 +275,12 @@ class ExternalImageInfoItem(InfoItem):
|
||||
|
||||
def get_template_url(self):
|
||||
"""Return External Image infoitem template url."""
|
||||
return "/static/html/generic_image.html?img={}".format(self.name)
|
||||
return "/static/infoscreen/html/generic_image.html?img={}".format(self.name)
|
||||
|
||||
@staticmethod
|
||||
def get_create_template_url():
|
||||
"""Call create External Image infoitem template url command."""
|
||||
return "/static/html/generic_external_image_create.html"
|
||||
return "/static/infoscreen/html/generic_external_image_create.html"
|
||||
|
||||
def get_dict(self):
|
||||
"""Convert django model to dict and return it."""
|
||||
@@ -321,7 +319,7 @@ class ExternalImageInfoItem(InfoItem):
|
||||
class InfoInstance(models.Model):
|
||||
"""Class for Info instance in Infoscreen."""
|
||||
|
||||
rotation = models.ForeignKey('Rotation', related_name='instances')
|
||||
rotation = models.ForeignKey('Rotation', related_name='instances', on_delete=models.CASCADE)
|
||||
duration = models.FloatField(default=15.0) # seconds
|
||||
# generic relation to some kind of InfoItem
|
||||
item_id = models.PositiveIntegerField()
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
table {
|
||||
font-size: 4vh;
|
||||
font-family: 'Droid Sans Mono', monospace;
|
||||
}
|
||||
.red {
|
||||
color: red;
|
||||
-webkit-animation-name: blinker;
|
||||
-webkit-animation-duration: 2s;
|
||||
-webkit-animation-timing-function: linear;
|
||||
-webkit-animation-iteration-count: infinite;
|
||||
|
||||
-moz-animation-name: blinker;
|
||||
-moz-animation-duration: 2s;
|
||||
-moz-animation-timing-function: linear;
|
||||
-moz-animation-iteration-count: infinite;
|
||||
|
||||
animation-name: blinker;
|
||||
animation-duration: 2s;
|
||||
animation-timing-function: linear;
|
||||
animation-iteration-count: infinite;
|
||||
}
|
||||
.black {
|
||||
color: black;
|
||||
}
|
||||
@-moz-keyframes blinker {
|
||||
0% { opacity: 1.0; }
|
||||
50% { opacity: 0.1; }
|
||||
100% { opacity: 1.0; }
|
||||
}
|
||||
|
||||
@-webkit-keyframes blinker {
|
||||
0% { opacity: 1.0; }
|
||||
50% { opacity: 0.1; }
|
||||
100% { opacity: 1.0; }
|
||||
}
|
||||
|
||||
@keyframes blinker {
|
||||
0% { opacity: 1.0; }
|
||||
50% { opacity: 0.1; }
|
||||
100% { opacity: 1.0; }
|
||||
}
|
||||
thead{
|
||||
background: #f0f0f0;
|
||||
}
|
||||
.header-row{
|
||||
background: #f0f0f0;
|
||||
font-size: 7vh;
|
||||
font-family: 'Droid Sans Mono', monospace;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.container {
|
||||
width: 100vw;
|
||||
padding: 0 0 0 0;
|
||||
}
|
||||
|
||||
.container .table {
|
||||
margin-left: 0;
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.repeat-item.ng-leave {
|
||||
|
||||
}
|
||||
|
||||
.repeat-item.ng-leave.ng-leave-active {
|
||||
opacity: 0;
|
||||
font-size: 0vh;
|
||||
}
|
||||
|
||||
.repeat-item.ng-leave{
|
||||
opacity: 1;
|
||||
font-size: 5vh;
|
||||
}
|
||||
@@ -1,4 +0,0 @@
|
||||
<link rel="stylesheet" href="/static/css/coffee.css">
|
||||
<iframe src="https://host2.kilta.aalto.fi/kahvi/cups" allowfullscreen=true sandbox="allow-scripts allow-pointer-lock allow-same-origin">
|
||||
<p>Your browser does not support iframes.</p>
|
||||
</iframe>
|
||||
@@ -1,41 +0,0 @@
|
||||
<link rel="stylesheet" href="/static/css/hsl.css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Droid+Sans+Mono" rel="stylesheet">
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.19.1/locale/fi.js"></script>
|
||||
<div class="container" ng-app="myApp" ng-controller="timetableCtrl">
|
||||
<div class="header-row row">
|
||||
<div class="col-sm-2"><p>{{clock | date:'HH:mm'}}</p></div>
|
||||
<div class="col-sm-8">HSL-Aikataulut</div>
|
||||
<div class="col-sm-2 time"></div>
|
||||
</div>
|
||||
<h1 style="font-size: 10vh; text-align: center" ng-if="error">
|
||||
{{error}}
|
||||
</h1>
|
||||
<table ng-if="!error" class="table table-striped row">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>
|
||||
Aika
|
||||
</th>
|
||||
<th>
|
||||
Linja
|
||||
</th>
|
||||
<th>
|
||||
Pysäkki
|
||||
</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="repeat-item" ng-repeat="x in stoptimes | orderBy: ['utc'] | limitTo: 11">
|
||||
<td style="min-width: 300px">
|
||||
{{x.timestamp}}
|
||||
</td>
|
||||
<td>
|
||||
<strong>{{x.route}}</strong>, {{x.headsign}}
|
||||
</td>
|
||||
<td>
|
||||
{{x.stop}}
|
||||
</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
@@ -1,10 +0,0 @@
|
||||
<div ng-controller="infoadmin_hslitem_create" style="margin-top:20px;">
|
||||
<div>
|
||||
Create new item to show hsl ttimetables. Name is used only as identifier
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Name:</label>
|
||||
<input type="text" ng-model="item.name"></input>
|
||||
</div>
|
||||
<input type="button" class="btn btn-success" ng-click="send()" value="create"></input>
|
||||
</div>
|
||||
@@ -1,20 +0,0 @@
|
||||
<link rel="stylesheet" href="/static/css/sosso.css">
|
||||
<div ng-controller="SossoController">
|
||||
<div id="header">
|
||||
<img id="header-image" src="/static/img/sossoheader.png" >
|
||||
</div>
|
||||
<div id="container">
|
||||
<div class="article-row row" ng-repeat="post in data.posts">
|
||||
<div class="article-thumb-col col-md-6">
|
||||
<img class="thumbnail" ng-src="{{ post.thumbnail_images['mh-edition-lite-medium'].url }}">
|
||||
</div>
|
||||
<div>
|
||||
<h1 class="col-md-6">
|
||||
<div class="article-title-col">
|
||||
{{ post.title }}
|
||||
</div>
|
||||
</h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1 +0,0 @@
|
||||
<h1>testi2</h1>
|
||||
@@ -1 +0,0 @@
|
||||
<h1>testi3</h1>
|
||||
|
Before Width: | Height: | Size: 101 KiB |
|
Before Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 163 KiB |
|
Before Width: | Height: | Size: 736 KiB |
|
Before Width: | Height: | Size: 1.8 MiB |
|
Before Width: | Height: | Size: 96 KiB |
@@ -2,7 +2,10 @@ body {
|
||||
font-family: 'Open Sans', sans-serif;
|
||||
}
|
||||
|
||||
#header {
|
||||
#header:after {
|
||||
content: " ";
|
||||
display: block;
|
||||
clear: both;
|
||||
}
|
||||
|
||||
#header-logo {
|
||||
@@ -5,6 +5,7 @@ html {
|
||||
body {
|
||||
padding: 1.5rem;
|
||||
margin: 0.5rem;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
tbody {
|
||||
@@ -49,7 +50,18 @@ td {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#header {
|
||||
max-width: 100%;
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
}
|
||||
|
||||
.tab-content {
|
||||
margin-top: 1rem;
|
||||
}
|
||||
|
||||
.rotation-title-row {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
#header {
|
||||
height: 30%;
|
||||
width: 100%;
|
||||
background-color:#7c1330;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
#header-image {
|
||||
display: block;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
max-width: 100%;
|
||||
}
|
||||
|
||||
.article-row {
|
||||
min-height: 20vh;
|
||||
margin: 10px 10px 10px 10px;
|
||||
}
|
||||
|
||||
.article-thumb-col {
|
||||
max-height: 200px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.article-title-col {
|
||||
font-size: 3vw;
|
||||
}
|
||||
|
||||
.thumbnail {
|
||||
max-width: 355px;
|
||||
max-height: 200px;
|
||||
}
|
||||
|
||||
#sossoimage {
|
||||
height: 300px;
|
||||
position: relative;
|
||||
left: 0px;
|
||||
top: 0px;
|
||||
}
|
||||
|
||||
.stretch {
|
||||
width:100%;
|
||||
height:100%;
|
||||
}
|
||||
|
||||
#post {
|
||||
height: 540px;
|
||||
border:2px solid black;
|
||||
}
|
||||
|
||||
#container {
|
||||
max-height: 70%;
|
||||
}
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
.article-thumb-col {
|
||||
max-height: 200px;
|
||||
text-align: right;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.article-title-col {
|
||||
@@ -1,10 +1,10 @@
|
||||
<link rel="stylesheet" href="/static/css/abb.css">
|
||||
<link rel="stylesheet" href="/static/infoscreen/css/abb.css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Open+Sans" rel="stylesheet">
|
||||
<div ng-controller="ABBController">
|
||||
<!-- Only show the job listing if there are any jobs, i.e, the jobs list is non-empty -->
|
||||
<div id="header" class="row" ng-if="jobs.length > 0">
|
||||
<div id="header-logo">
|
||||
<img src="/static/img/ABB_logo.png">
|
||||
<img src="/static/infoscreen/img/ABB_logo.png">
|
||||
</div>
|
||||
<div id="header-title">
|
||||
TYÖPAIKAT
|
||||
@@ -28,6 +28,6 @@
|
||||
|
||||
<!-- If there are no jobs, show a static image -->
|
||||
<div class="row" ng-if="jobs.length == 0">
|
||||
<img src="/static/img/ABB_uralle.png" style="position:absolute;left:0;top:0;width:100vw;">
|
||||
<img src="/static/infoscreen/img/ABB_uralle.png" style="position:absolute;left:0;top:0;width:100vw;">
|
||||
</div>
|
||||
</div>
|
||||
@@ -4,7 +4,7 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Name:</label>
|
||||
<input type="text" ng-model="item.name"></input>
|
||||
<input class="form-control" type="text" ng-model="item.name"></input>
|
||||
</div>
|
||||
<input type="button" class="btn btn-success" ng-click="send()" value="create"></input>
|
||||
</div>
|
||||
@@ -1,4 +1,4 @@
|
||||
<link rel="stylesheet" href="/static/css/apy.css">
|
||||
<link rel="stylesheet" href="/static/infoscreen/css/apy.css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro" rel="stylesheet">
|
||||
<div id="bg">
|
||||
<div class="container " ng-controller="ApyController">
|
||||
@@ -1,10 +1,10 @@
|
||||
<div ng-controller="infoadmin_apyitem_create" style="margin-top:20px;">
|
||||
<div>
|
||||
create apyitem
|
||||
Create new ÄPY statistics item
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Name:</label>
|
||||
<input type="text" ng-model="item.name"></input>
|
||||
<input class="form-control" type="text" ng-model="item.name"></input>
|
||||
</div>
|
||||
<input type="button" class="btn btn-success" ng-click="send()" value="create"></input>
|
||||
</div>
|
||||
@@ -1,4 +1,4 @@
|
||||
<link rel="stylesheet" href="/static/css/events.css">
|
||||
<link rel="stylesheet" href="/static/infoscreen/css/events.css">
|
||||
<link href="https://fonts.googleapis.com/css?family=Droid+Sans+Mono" rel="stylesheet">
|
||||
<div class="container" ng-app="myApp" ng-controller="EventController">
|
||||
<div class="header-row row">
|
||||
@@ -4,7 +4,7 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Name:</label>
|
||||
<input type="text" ng-model="item.name"></input>
|
||||
<input type="text" class="form-control" ng-model="item.name"></input>
|
||||
</div>
|
||||
<input type="button" class="btn btn-success" ng-click="send()" value="create"></input>
|
||||
</div>
|
||||
@@ -1,4 +1,4 @@
|
||||
<link rel="stylesheet" href="/static/css/external_website.css">
|
||||
<link rel="stylesheet" href="/static/infoscreen/css/external_website.css">
|
||||
<iframe ng-src="{{ url | trusted_url }}" allowfullscreen=true sandbox="allow-scripts allow-pointer-lock allow-same-origin">
|
||||
<p>Your browser does not support iframes.</p>
|
||||
</iframe>
|
||||
@@ -1,14 +1,14 @@
|
||||
<div ng-controller="infoadmin_websiteitem_create" style="margin-top:20px;">
|
||||
<div>
|
||||
Create new item to show external website. For example "ka.dy.fi".
|
||||
Create new item to show external website. For example "https://ka.dy.fi".
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Name:</label>
|
||||
<input type="text" ng-model="item.name"></input>
|
||||
<input type="text" class="form-control" ng-model="item.name"></input>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Url:</label>
|
||||
<input type="text" ng-model="item.url"></input>
|
||||
<input type="text" class="form-control" ng-model="item.url"></input>
|
||||
</div>
|
||||
<input type="button" class="btn btn-success" ng-click="send()" value="create"></input>
|
||||
</div>
|
||||
@@ -4,11 +4,11 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Name:</label>
|
||||
<input type="text" ng-model="item.name"></input>
|
||||
<input type="text" class="form-control" ng-model="item.name"></input>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Url:</label>
|
||||
<input type="text" ng-model="item.url"></input>
|
||||
<input type="text" class="form-control" ng-model="item.url"></input>
|
||||
</div>
|
||||
<input type="button" class="btn btn-success" ng-click="send()" value="create"></input>
|
||||
</div>
|
||||
@@ -4,7 +4,7 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Name:</label>
|
||||
<input type="text" ng-model="imagename"></input>
|
||||
<input type="text" class="form-control" ng-model="imagename"></input>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="file" ngf-select ng-model="img" name="file" required>
|
||||
@@ -1,4 +1,4 @@
|
||||
<link rel="stylesheet" href="/static/css/video.css">
|
||||
<link rel="stylesheet" href="/static/infoscreen/css/video.css">
|
||||
|
||||
|
||||
<div class="fullscreen-bg">
|
||||
@@ -4,7 +4,7 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Name:</label>
|
||||
<input type="text" ng-model="name"></input>
|
||||
<input type="text" class="form-control" ng-model="name"></input>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<input type="file" ngf-select ng-model="video" name="file" required>
|
||||
@@ -0,0 +1,11 @@
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="/static/infoscreen/css/lunch.css">
|
||||
<div ng-controller="LunchController">
|
||||
<div id="container">
|
||||
<div class="restaurant row" ng-repeat="restaurant in data">
|
||||
<div class="lunch-option" ng-repeat="l in lunch">
|
||||
<h3 ng-bind-html="l.title | unsafe"></h3>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,10 @@
|
||||
<div ng-controller="infoadmin_lunchitem_create" style="margin-top:20px;">
|
||||
<div>
|
||||
Create new item to show restaurants. Name is used only as identifier
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Name:</label>
|
||||
<input type="text" class="form-control" ng-model="item.name"></input>
|
||||
</div>
|
||||
<input type="button" class="btn btn-success" ng-click="send()" value="create"></input>
|
||||
</div>
|
||||
@@ -0,0 +1,17 @@
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-alpha.6/css/bootstrap.min.css" integrity="sha384-rwoIResjU2yc3z8GV/NPeZWAv56rSmLldC3R/AZzGRnGxQQKnKkoFVhFQhNUwEyJ" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="/static/infoscreen/css/sosso.css">
|
||||
<div ng-controller="SossoController">
|
||||
<div id="header">
|
||||
<img id="header-image" src="/static/infoscreen/img/sossoheader.png" >
|
||||
</div>
|
||||
<div id="container">
|
||||
<div class="article-row row" ng-repeat="post in data.posts">
|
||||
<div class="article-thumb-col col-md-4">
|
||||
<img class="thumbnail" ng-src="{{ post.thumbnail_images['mh-edition-lite-medium'].url }}">
|
||||
</div>
|
||||
<div class="col-md-8 article-title-col">
|
||||
<h1 ng-bind-html="post.title | unsafe"></h1>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -4,7 +4,7 @@
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label>Name:</label>
|
||||
<input type="text" ng-model="item.name"></input>
|
||||
<input type="text" class="form-control" ng-model="item.name"></input>
|
||||
</div>
|
||||
<input type="button" class="btn btn-success" ng-click="send()" value="create"></input>
|
||||
</div>
|
||||
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 80 KiB After Width: | Height: | Size: 80 KiB |
|
Before Width: | Height: | Size: 49 KiB After Width: | Height: | Size: 49 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
@@ -182,8 +182,8 @@ var simple_controllers = [
|
||||
"external_image",
|
||||
"abbitem",
|
||||
"sossoitem",
|
||||
"lunchitem",
|
||||
"eventitem",
|
||||
"hslitem",
|
||||
"websiteitem",
|
||||
"apyitem",
|
||||
];
|
||||
@@ -46,6 +46,13 @@ app.filter('trusted_url', ['$sce', function ($sce) {
|
||||
};
|
||||
}]);
|
||||
|
||||
//Used for special characters in Sosso. This may open up XSS, so we need to trust that sosso.fi doesn't get compromised...
|
||||
app.filter('unsafe', function($sce) {
|
||||
return function(val) {
|
||||
return $sce.trustAsHtml(val);
|
||||
};
|
||||
});
|
||||
|
||||
app.controller('ABBController', function($scope, $http){
|
||||
$scope.jobs = [];
|
||||
var min_date = moment().subtract(30,'days').format("YYYY-MM-DD%20HH:mm:ss");
|
||||
@@ -75,6 +82,21 @@ app.controller('SossoController', function($scope, $http) {
|
||||
})
|
||||
});
|
||||
|
||||
app.controller('LunchController', function ($scope, $http) {
|
||||
$scope.data = [];
|
||||
var restaurants = [42];
|
||||
var restaurant_names = ["TUAS"]
|
||||
var cur_date = new Date().toISOString().split("T")[0]
|
||||
$http.get("https://kitchen.kanttiinit.fi/menus?restaurants=" + restaurants.join(",") + "&days=" + cur_date).then(function (response) {
|
||||
$scope.data = restaurant_names.map(function(n, idx) {
|
||||
return {
|
||||
name: n,
|
||||
lunch: response[idx][cur_date],
|
||||
}
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
app.controller('ApyController', function($scope, $http) {
|
||||
$scope.items = [];
|
||||
$http.get("/infoscreen/apyjson").then(function(response)
|
||||
@@ -112,35 +134,3 @@ app.filter('unixTimeToDifference', function() {
|
||||
return res;
|
||||
}
|
||||
})
|
||||
|
||||
app.controller('timetableCtrl',
|
||||
function($scope, $http, $interval) {
|
||||
function load() {
|
||||
$http.get('/infoscreen/hsl_data')
|
||||
.then(function(data, status, headers, config) { //eslint-disable-line no-unused-vars
|
||||
$scope.stoptimes = data.data;
|
||||
$scope.error = data.data.error || null;
|
||||
});
|
||||
$http.get('/infoscreen/hsl_data/settings')
|
||||
.then(function(data, status, headers, config) { //eslint-disable-line no-unused-vars
|
||||
$scope.departureThreshold = data.data['departure_threshold'];
|
||||
$scope.hurryThreshold = data.data['hurry_threshold'];
|
||||
});
|
||||
}
|
||||
|
||||
function update_clock() {
|
||||
$scope.clock = Date.now();
|
||||
}
|
||||
|
||||
$scope.$on('$destroy', function() {
|
||||
$interval.cancel(load_interval);
|
||||
$interval.cancel(clock_interval);
|
||||
});
|
||||
|
||||
var load_interval = $interval(load, 5000);
|
||||
var clock_interval = $interval(update_clock, 1000);
|
||||
|
||||
update_clock();
|
||||
load();
|
||||
}
|
||||
);
|
||||
@@ -0,0 +1,44 @@
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% load staticfiles %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
|
||||
{% block html %}
|
||||
<html ng-app="{% block appname %}{% endblock appname %}">
|
||||
<head>
|
||||
<meta charset="utf-8" name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1" />
|
||||
<title>
|
||||
{% block title %}
|
||||
{% endblock title %}
|
||||
</title>
|
||||
|
||||
{% block libraries %}
|
||||
<script src="{% static "js/lib/angular.js" %}"></script>
|
||||
<script src="{% static "js/lib/ng-file-upload-bower-12.2.11/ng-file-upload-all.js" %}"></script>
|
||||
<script src="{% static "js/lib/jquery-3.1.0.min.js" %}"></script>
|
||||
<script src="{% static "js/lib/underscore-min.js" %}"></script>
|
||||
<script src="{% static "js/lib/moment.js" %}"></script>
|
||||
<script src="{% static "js/lib/angular-route.js" %}"></script>
|
||||
<script src="{% static "js/lib/angular-animate.js" %}"></script>
|
||||
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
|
||||
<script src="https://cdnjs.cloudflare.com/ajax/libs/tether/1.4.0/js/tether.min.js" integrity="sha384-DztdAPBWPRXSA/3eYEEUWrWCy7G5KFbe8fFjk5JAIxUYHKkDx6Qin1DkWx51bBrb" crossorigin="anonymous"></script>
|
||||
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
|
||||
{% endblock libraries %}
|
||||
|
||||
{% block styles %}
|
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
|
||||
<link rel="stylesheet" href="{% static "webapp/css/footer.css" %}">
|
||||
{% endblock styles %}
|
||||
|
||||
{% block controllers %}
|
||||
<script src="{% static "infoscreen/js/infoadmin_controllers.js" %}"></script>
|
||||
{% endblock controllers %}
|
||||
</head>
|
||||
<body>
|
||||
{% block body %}
|
||||
{% endblock body %}
|
||||
</body>
|
||||
</html>
|
||||
{% endblock html %}
|
||||
@@ -0,0 +1,7 @@
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
<div class="header-content">
|
||||
<div class="logo">
|
||||
<a href="/"><img src="{% static "webapp/img/logo_header.png" %}" alt="Aalto-yliopiston Sähköinsinöörikilta ry"></a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,154 +1,45 @@
|
||||
{% extends "infoscreen:base.html" %}
|
||||
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
{% load staticfiles %}
|
||||
<!DOCTYPE html>
|
||||
<html ng-app="infoAdmin">
|
||||
<head>
|
||||
<meta charset="utf-8" name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1" />
|
||||
<title>Infoscreen admin</title>
|
||||
<script src="{% static "js/lib/angular.js" %}"></script>
|
||||
<script src="{% static "js/lib/ng-file-upload-bower-12.2.11/ng-file-upload-all.js" %}"></script>
|
||||
<script src="{% static "js/lib/jquery-3.1.0.min.js" %}"></script>
|
||||
<script src="{% static "js/lib/bootstrap.min.js" %}"></script>
|
||||
<script src="{% static "js/lib/underscore-min.js" %}"></script>
|
||||
<script src="{% static "js/infoadmin_controllers.js" %}"></script>
|
||||
|
||||
<link rel="stylesheet" href="{% static "css/lib/bootstrap.min.css" %}"></link>
|
||||
<link rel="stylesheet" href="{% static "css/base.css" %}"></link>
|
||||
<link rel="stylesheet" href="{% static "css/infoscreen_admin.css" %}"></link>
|
||||
</head>
|
||||
<body>
|
||||
<div id="header" class="row">
|
||||
<div class="logout-button">
|
||||
<form action="/logout" method="post"> {% csrf_token %}
|
||||
<input type="Submit" value="{% trans "Log out" %}" name="Logout" class="btn btn-danger"/>
|
||||
</form>
|
||||
</div>
|
||||
{% block appname %}infoAdmin{% endblock appname %}
|
||||
|
||||
{% block title %}
|
||||
{% trans "Infoscreen admin" %}
|
||||
{% endblock title %}
|
||||
|
||||
{% block styles %}
|
||||
{{ block.super }}
|
||||
<link rel="stylesheet" href="{% static "infoscreen/css/admin.css" %}"></link>
|
||||
{% endblock styles %}
|
||||
|
||||
{% block controllers %}
|
||||
<script src="{% static "infoscreen/js/infoadmin_controllers.js" %}"></script>
|
||||
{% endblock controllers %}
|
||||
|
||||
{% block body %}
|
||||
<div id="header" class="row">
|
||||
<div class="logout-button">
|
||||
<form action="/admin/logout/" method="post"> {% csrf_token %}
|
||||
<input type="Submit" value="{% trans "Log out" %}" name="Logout" class="btn btn-danger"/>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
<div class="container" ng-controller="infoadmin_ctrl">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<h1>{% trans "Infoscreen Admin Pane" %}</h1>
|
||||
</div>
|
||||
<div class="container" ng-controller="infoadmin_ctrl">
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
<h1>{% trans "Infoscreen Admin Pane" %}</h1>
|
||||
</div>
|
||||
</div>
|
||||
<ul class="nav nav-tabs" role="tablist">
|
||||
<li class="active"><a data-toggle="tab" href="#slides" role="tab">{% trans "Manage Slides" %}</a></li>
|
||||
<li class="dropdown">
|
||||
<a data-toggle="dropdown" href="#">{% trans "Manage Rotations" %}<span class="caret"></span></a>
|
||||
<ul class="dropdown-menu">
|
||||
<li ng-repeat="r in rotations"><a href="#rotations" ng-click="selectRotation(r.id)" data-toggle="tab">{$ r.name $}</a></li>
|
||||
<li class="divider">
|
||||
<li class="nav-item"><a data-toggle="tab" href="#deleterot" role="tab">{% trans "Create/Delete" %}</a></li>
|
||||
</ul>
|
||||
</ul>
|
||||
<div class="tab-content row">
|
||||
<div id="slides" class="tab-pane active">
|
||||
<div ng-controller="infoadmin_ctrl">
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<h2>{% trans "Create new item" %}</h2>
|
||||
<div>{% trans "Create a new item by type" %}</div>
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<td>{% trans "Item type" %}</td>
|
||||
<td>
|
||||
<select class="form-control form-control-sm" ng-model="createtype", ng-options="t.name for t in infotypes | orderBy: 'name'">
|
||||
<option value=""></option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div ng-include="createtype.create_template_url"></div>
|
||||
</div>
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<h2>{% trans "Info items" %}</h2>
|
||||
<div>{% trans "Infoitems available for rotations" %}</div>
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>{% trans "Item" %}</th>
|
||||
<th>{% trans "Type" %}</th>
|
||||
<th>{% trans "Delete" %}</th>
|
||||
</tr>
|
||||
<tr ng-repeat="i in infoitems | orderBy:['display_name','name']">
|
||||
<td>{$ i.name $}</td>
|
||||
<td>{$ i.display_name $}</td>
|
||||
<td><input type="button" class="btn btn-danger" ng-click="deleteItem(i.item_type, i.id);" value="{% trans "Delete" %}"></input></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
{% include "infoscreen:nav.html" %}
|
||||
<div class="tab-content" id="tabContent">
|
||||
{% include "infoscreen:tabs/slides.html" %}
|
||||
{% include "infoscreen:tabs/rotations.html" %}
|
||||
{% include "infoscreen:tabs/add_remove.html" %}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="rotations" class="tab-pane" ng-controller="infoadmin_ctrl">
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<h2>{% trans "Info items" %}</h2>
|
||||
<div>{% trans "Infoitems available for rotations" %}</div>
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>{% trans "Item" %}</th>
|
||||
<th>{% trans "Type" %}</th>
|
||||
<th>{% trans "Set duration" %}</th>
|
||||
<th>{% trans "Add to rotation" %}</th>
|
||||
<th>{% trans "Delete" %}</th>
|
||||
</tr>
|
||||
<tr ng-repeat="i in infoitems | orderBy:['display_name','name']">
|
||||
<td>{$ i.name $}</td>
|
||||
<td>{$ i.display_name $}</td>
|
||||
<td><input type="number" min="1" max="60" class="form-control" ng-model="i.duration"></input></td>
|
||||
<td><input type="button" class="btn btn-success" ng-click="createInstance(selected_rot.id, i.id, i.item_type, i.duration);" value="{% trans "Add" %}"></input></td>
|
||||
<td><input type="button" class="btn btn-danger" ng-click="deleteItem(i.item_type, i.id);" value="{% trans "Delete" %}"></input></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col-xs-12 col-md-6">
|
||||
<h2>{% trans "Rotation" %}: {$ selected_rot.name $}<a href="/infoscreen/{$ selected_rot.id $}"><input type="button" class="btn btn-primary pull-right" value="{% trans "Preview" %}"></a></h2>
|
||||
<div>{% trans "Instances in currently selected rotation" %}:</div>
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>{% trans "Instance" %}</th>
|
||||
<th>{% trans "Duration" %}</th>
|
||||
<th>{% trans "Delete" %}</th>
|
||||
</tr>
|
||||
<tr ng-repeat="i in selected_rot.instances">
|
||||
<td>{$ i.item.name $}</td><td>{$ i.duration $} s</td>
|
||||
<td><input type="button" ng-click="deleteInstance(i.id);" value="{% trans "Delete" %}" class="btn btn-danger"></input></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
<div id="deleterot" class="tab-pane">
|
||||
<div class="col-xs-12 " ng-controller="infoadmin_ctrl">
|
||||
<h2>{% trans "Rotations" %}</h2>
|
||||
<div>
|
||||
{% trans "Select rotation to edit" %}:
|
||||
</div>
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>{% trans "Rotation" %}</th>
|
||||
<th>{% trans "id" %}</th>
|
||||
<th>{% trans "Preview" %}</th>
|
||||
<th>{% trans "Delete" %}</th>
|
||||
</tr>
|
||||
<tr ng-repeat="r in rotations">
|
||||
<td>{$ r.name $}</td>
|
||||
<td>{$ r.id $}</td>
|
||||
<td><a href="/infoscreen/{$ r.id $}"><input type="button" class="btn btn-primary" value="{% trans "Preview" %}"></a></td>
|
||||
<td><input type="button" class="btn btn-danger" ng-click="deleteRotation(r.id)" value="{% trans "Delete" %}"></input></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="text" class="form-control" ng-model="r.name" placeholder="{% trans "Name" %}"></input></td>
|
||||
<td><input type="button" class="btn btn-success" ng-click="createRotation(r.name)" value="{% trans "Create new" %}"></input></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div style="margin-top: 100px;">
|
||||
{% include "footer.html" %}
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
{% include "webapp:footer.html" %}
|
||||
{% endblock body %}
|
||||
@@ -1,29 +1,25 @@
|
||||
{% extends "infoscreen:base.html" %}
|
||||
{% load static %}
|
||||
{% load i18n %}
|
||||
|
||||
<!DOCTYPE html>
|
||||
<html ng-app="infoApp">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
{% block appname %}infoApp{% endblock appname %}
|
||||
|
||||
<title>Infoscreen</title>
|
||||
<script src="{% static "js/lib/moment.js" %}"></script>
|
||||
<script src="{% static "js/lib/angular.js" %}"></script>
|
||||
<script src="{% static "js/lib/angular-route.js" %}"></script>
|
||||
<script src="{% static "js/lib/angular-animate.js" %}"></script>
|
||||
<script src="{% static "js/lib/jquery-3.1.0.min.js" %}"></script>
|
||||
<script src="{% static "js/lib/bootstrap.min.js" %}"></script>
|
||||
<script src="{% static "js/lib/underscore-min.js" %}"></script>
|
||||
<script src="{% static "js/infoscreen_controllers.js" %}"></script>
|
||||
{% block title %}
|
||||
{% trans "Infoscreen" %}
|
||||
{% endblock title %}
|
||||
|
||||
<link rel="stylesheet" href="{% static "css/lib/bootstrap.min.css" %}"></link>
|
||||
<link rel="stylesheet" href="{% static "css/infoscreen.css" %}"></link>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container ng-scope" ng-controller="infoscreen_main" ng-init="init({{ rotation }})">
|
||||
<div ng-animate-swap="index" class="cell swap-animation">
|
||||
<div id="infocontent" ng-include="active.template" onload="active.onload()"></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
{% block controllers %}
|
||||
<script src="{% static "infoscreen/js/infoscreen_controllers.js" %}"></script>
|
||||
{% endblock controllers %}
|
||||
|
||||
{% block styles %}
|
||||
<link rel="stylesheet" href="{% static "infoscreen/css/infoscreen.css" %}"></link>
|
||||
{% endblock styles %}
|
||||
|
||||
{% block body %}
|
||||
<div class="container ng-scope" ng-controller="infoscreen_main" ng-init="init({{ rotation }})">
|
||||
<div ng-animate-swap="index" class="cell swap-animation">
|
||||
<div id="infocontent" ng-include="active.template" onload="active.onload()"></div>
|
||||
</div>
|
||||
</div>
|
||||
{% endblock body %}
|
||||
@@ -0,0 +1,17 @@
|
||||
{% load i18n %}
|
||||
|
||||
<ul class="nav nav-tabs" id="tabs" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" data-toggle="tab" role="tab" href="#slides">{% trans "Manage Slides" %}</a>
|
||||
</li>
|
||||
<li class="nav-item dropdown">
|
||||
<a class="nav-link dropdown-toggle" role="button" data-toggle="dropdown" href="#" aria-haspopup="true" aria-expanded="false">
|
||||
{% trans "Manage Rotations" %}<span class="caret"></span>
|
||||
</a>
|
||||
<div class="dropdown-menu">
|
||||
<a class="dropdown-item" role="tab" href="#rotations" ng-repeat="r in rotations" ng-click="selectRotation(r.id)" data-toggle="tab">{$ r.name $}</a>
|
||||
<div class="dropdown-divider"></div>
|
||||
<a class="dropdown-item" data-toggle="tab" href="#deleterot" role="tab">{% trans "Create/Delete" %}</a>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
@@ -0,0 +1,30 @@
|
||||
{% load i18n %}
|
||||
|
||||
<div id="deleterot" class="tab-pane fade" role="tabpanel">
|
||||
<div class="col" ng-controller="infoadmin_ctrl">
|
||||
<h2>{% trans "Rotations" %}</h2>
|
||||
<div>
|
||||
{% trans "Select rotation to edit" %}:
|
||||
</div>
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>{% trans "Rotation" %}</th>
|
||||
<th>{% trans "id" %}</th>
|
||||
<th>{% trans "Preview" %}</th>
|
||||
<th>{% trans "Delete" %}</th>
|
||||
</tr>
|
||||
<tr ng-repeat="r in rotations">
|
||||
<td>{$ r.name $}</td>
|
||||
<td>{$ r.id $}</td>
|
||||
<td><a class="btn btn-primary" href="/infoscreen/{$ r.id $}">{% trans "Preview" %}</a></td>
|
||||
<td><a class="btn btn-danger" href="#" ng-click="deleteRotation(r.id)">{% trans "Delete" %}</a></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input type="text" class="form-control" ng-model="r.name" placeholder="{% trans "Name" %}"></input></td>
|
||||
<td><input type="button" class="btn btn-success" ng-click="createRotation(r.name)" value="{% trans "Create new" %}"></input></td>
|
||||
<td></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,44 @@
|
||||
{% load i18n %}
|
||||
|
||||
<div id="rotations" class="tab-pane fade" role="tabpanel" ng-controller="infoadmin_ctrl">
|
||||
<div class="col">
|
||||
<h2>{% trans "Info items" %}</h2>
|
||||
<div>{% trans "Infoitems available for rotations" %}</div>
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>{% trans "Item" %}</th>
|
||||
<th>{% trans "Type" %}</th>
|
||||
<th>{% trans "Set duration" %}</th>
|
||||
<th>{% trans "Add to rotation" %}</th>
|
||||
<th>{% trans "Delete" %}</th>
|
||||
</tr>
|
||||
<tr ng-repeat="i in infoitems | orderBy:['display_name','name']">
|
||||
<td>{$ i.name $}</td>
|
||||
<td>{$ i.display_name $}</td>
|
||||
<td><input type="number" min="1" max="60" class="form-control" ng-model="i.duration"></input></td>
|
||||
<td><input type="button" class="btn btn-success" ng-click="createInstance(selected_rot.id, i.id, i.item_type, i.duration);" value="{% trans "Add" %}"></input></td>
|
||||
<td><input type="button" class="btn btn-danger" ng-click="deleteItem(i.item_type, i.id);" value="{% trans "Delete" %}"></input></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="col">
|
||||
<div class="rotation-title-row">
|
||||
<h2>{% trans "Rotation" %}: {$ selected_rot.name $}</h2>
|
||||
<a class="btn btn-primary" href="/infoscreen/{$ selected_rot.id $}">{% trans "Preview" %}</a>
|
||||
</div>
|
||||
<div>{% trans "Instances in currently selected rotation" %}:</div>
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>{% trans "Instance" %}</th>
|
||||
<th>{% trans "Duration" %}</th>
|
||||
<th>{% trans "Delete" %}</th>
|
||||
</tr>
|
||||
<tr ng-repeat="i in selected_rot.instances">
|
||||
<td>{$ i.item.name $}</td><td>{$ i.duration $} s</td>
|
||||
<td><input type="button" ng-click="deleteInstance(i.id);" value="{% trans "Delete" %}" class="btn btn-danger"></input></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,37 @@
|
||||
{% load i18n %}
|
||||
|
||||
<div id="slides" class="tab-pane fade show active" role="tabpanel">
|
||||
<div ng-controller="infoadmin_ctrl">
|
||||
<div class="col">
|
||||
<h2>{% trans "Create new item" %}</h2>
|
||||
<div>{% trans "Create a new item by type" %}</div>
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<td>{% trans "Item type" %}</td>
|
||||
<td>
|
||||
<select class="form-control form-control-sm" ng-model="createtype", ng-options="t.name for t in infotypes | orderBy: 'name'">
|
||||
<option value=""></option>
|
||||
</select>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<div ng-include="createtype.create_template_url"></div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<h2>{% trans "Info items" %}</h2>
|
||||
<div>{% trans "Infoitems available for rotations" %}</div>
|
||||
<table class="table table-striped">
|
||||
<tr>
|
||||
<th>{% trans "Item" %}</th>
|
||||
<th>{% trans "Type" %}</th>
|
||||
<th>{% trans "Delete" %}</th>
|
||||
</tr>
|
||||
<tr ng-repeat="i in infoitems | orderBy:['display_name','name']">
|
||||
<td>{$ i.name $}</td>
|
||||
<td>{$ i.display_name $}</td>
|
||||
<td><input type="button" class="btn btn-danger" ng-click="deleteItem(i.item_type, i.id);" value="{% trans "Delete" %}"></input></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1,6 +1,7 @@
|
||||
"""File containing infoscreen urls."""
|
||||
|
||||
from django.conf.urls import url
|
||||
from django.conf import settings
|
||||
|
||||
from infoscreen.views import index
|
||||
from infoscreen.views import admin
|
||||
@@ -17,14 +18,12 @@ from infoscreen.views import create_image_item
|
||||
from infoscreen.views import create_video_item
|
||||
from infoscreen.views import createABBItem
|
||||
from infoscreen.views import createSossoItem
|
||||
from infoscreen.views import createHslItem
|
||||
from infoscreen.views import createLunchItem
|
||||
from infoscreen.views import createEventItem
|
||||
from infoscreen.views import createExternalWebsiteItem
|
||||
from infoscreen.views import create_rotation
|
||||
from infoscreen.views import delete_rotation
|
||||
from infoscreen.views import CurrentHSLView
|
||||
from infoscreen.views import createApyItem
|
||||
from infoscreen.views import hsl_timetable_settings
|
||||
from infoscreen.views import get_apy_json
|
||||
|
||||
urlpatterns = [
|
||||
@@ -43,14 +42,15 @@ urlpatterns = [
|
||||
url(r'^create_video$', create_video_item),
|
||||
url(r'^create_abbitem$', createABBItem),
|
||||
url(r'^create_sossoitem$', createSossoItem),
|
||||
url(r'^create_lunchitem$', createLunchItem),
|
||||
url(r'^create_eventitem$', createEventItem),
|
||||
url(r'^create_hslitem$', createHslItem),
|
||||
url(r'^create_apyitem$', createApyItem),
|
||||
url(r'^create_websiteitem$', createExternalWebsiteItem),
|
||||
url(r'^create_rotation$', create_rotation),
|
||||
url(r'^delete_rotation/(?P<id>\d+)$', delete_rotation),
|
||||
url(r'^hsl_data$', CurrentHSLView),
|
||||
url(r'^hsl_data/settings$', hsl_timetable_settings),
|
||||
url(r'^apyjson', get_apy_json),
|
||||
|
||||
]
|
||||
|
||||
if settings.DEBUG:
|
||||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||
urlpatterns += staticfiles_urlpatterns()
|
||||
|
||||
@@ -6,6 +6,7 @@ from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
from django.views.decorators.http import require_http_methods
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.contrib.auth.decorators import permission_required, login_required
|
||||
from django.db import DatabaseError
|
||||
from infoscreen.models import UploadFileForm
|
||||
|
||||
import sikweb.settings as settings
|
||||
@@ -14,21 +15,17 @@ import logging
|
||||
import threading
|
||||
import requests
|
||||
|
||||
from infoscreen.models import Rotation, InfoItem, InfoInstance
|
||||
from infoscreen.models import (ABBInfoItem, ExternalImageInfoItem,
|
||||
ImageInfoItem, SossoInfoItem, HslInfoItem)
|
||||
from infoscreen.models import EventInfoItem
|
||||
from infoscreen.models import ExternalWebsiteInfoItem
|
||||
from infoscreen.models import ImageUploadForm
|
||||
from infoscreen.models import ApyInfoItem
|
||||
from infoscreen.models import VideoInfoItem
|
||||
from infoscreen.models import (
|
||||
Rotation, InfoItem, InfoInstance, ABBInfoItem, ExternalImageInfoItem,
|
||||
ImageInfoItem, SossoInfoItem, LunchItem, EventInfoItem,
|
||||
ExternalWebsiteInfoItem, ImageUploadForm, ApyInfoItem, VideoInfoItem)
|
||||
|
||||
|
||||
@login_required(login_url='/login')
|
||||
@login_required(login_url='/admin/login')
|
||||
@permission_required('infoscreen.change_infoinstance', raise_exception=True)
|
||||
def admin(request, *args, **kwargs):
|
||||
"""Render infoscreen admin page."""
|
||||
return render(request, 'infoscreen_admin.html', {})
|
||||
return render(request, 'infoscreen:infoscreen_admin.html', {})
|
||||
|
||||
|
||||
def create_item_generator(model):
|
||||
@@ -36,12 +33,12 @@ def create_item_generator(model):
|
||||
|
||||
@ensure_csrf_cookie
|
||||
@require_http_methods(["POST"])
|
||||
@login_required(login_url='/login')
|
||||
@login_required(login_url='/admin/login')
|
||||
@permission_required('infoscreen.add_infoinstance', raise_exception=True)
|
||||
def create_item(request, *args, **kwargs):
|
||||
try:
|
||||
data = json.loads(request.body.decode("utf-8"))
|
||||
except ValueError:
|
||||
except json.JSONDecodeError:
|
||||
return HttpResponseBadRequest(
|
||||
'{"status":"failure","error":"invalid json supplied"}')
|
||||
try:
|
||||
@@ -58,7 +55,7 @@ def delete_item_generator(model):
|
||||
|
||||
@ensure_csrf_cookie
|
||||
@require_http_methods(["DELETE"])
|
||||
@login_required(login_url='/login')
|
||||
@login_required(login_url='/admin/login')
|
||||
@permission_required('infoscreen.delete_infoinstance', raise_exception=True)
|
||||
def delete_item(request, *args, **kwargs):
|
||||
idx = kwargs.pop("idx", 0)
|
||||
@@ -71,7 +68,7 @@ def delete_item_generator(model):
|
||||
try:
|
||||
item.delete()
|
||||
return HttpResponse('{"status":"success"}')
|
||||
except:
|
||||
except DatabaseError:
|
||||
resp = HttpResponse('{"error" : "could not delete item"}')
|
||||
resp.status_code = 500
|
||||
return resp
|
||||
@@ -80,7 +77,7 @@ def delete_item_generator(model):
|
||||
|
||||
# due to model structure this is little complicated
|
||||
@ensure_csrf_cookie
|
||||
@login_required(login_url='/login')
|
||||
@login_required(login_url='/admin/login')
|
||||
@permission_required('infoscreen.delete_infoinstance', raise_exception=True)
|
||||
@require_http_methods(["DELETE"])
|
||||
def delete_info_item(request, *args, **kwargs):
|
||||
@@ -97,7 +94,7 @@ def delete_info_item(request, *args, **kwargs):
|
||||
try:
|
||||
item.delete()
|
||||
return HttpResponse('{"status":"success"}')
|
||||
except:
|
||||
except DatabaseError:
|
||||
resp = HttpResponse('{"error" : "could not delete item"}')
|
||||
resp.status_code = 500
|
||||
return resp
|
||||
@@ -105,7 +102,7 @@ def delete_info_item(request, *args, **kwargs):
|
||||
|
||||
@require_http_methods(["POST"])
|
||||
@ensure_csrf_cookie
|
||||
@login_required(login_url='/login')
|
||||
@login_required(login_url='/admin/login')
|
||||
@permission_required('infoscreen.add_infoinstance', raise_exception=True)
|
||||
def create_image_item(request, *args, **kwargs):
|
||||
"""Create image Infoscreen item."""
|
||||
@@ -122,7 +119,7 @@ def create_image_item(request, *args, **kwargs):
|
||||
|
||||
@require_http_methods(["POST"])
|
||||
@ensure_csrf_cookie
|
||||
@login_required(login_url='/login')
|
||||
@login_required(login_url='/admin/login')
|
||||
@permission_required('infoscreen.add_infoinstance', raise_exception=True)
|
||||
def create_video_item(request, *args, **kwargs):
|
||||
"""Create video Infoscreen item."""
|
||||
@@ -139,20 +136,20 @@ def create_video_item(request, *args, **kwargs):
|
||||
|
||||
@require_http_methods(["POST"])
|
||||
@ensure_csrf_cookie
|
||||
@login_required(login_url='/login')
|
||||
@login_required(login_url='/admin/login')
|
||||
@permission_required('infoscreen.add_rotation', raise_exception=True)
|
||||
def create_rotation(request, *args, **kwargs):
|
||||
"""Create rotation."""
|
||||
try:
|
||||
data = json.loads(request.body.decode("utf-8"))
|
||||
except:
|
||||
except json.JSONDecodeError:
|
||||
return HttpResponse('{"error": "bad post body!"}', status=400)
|
||||
|
||||
try:
|
||||
name = data["name"]
|
||||
Rotation.objects.create(name=name)
|
||||
resp = HttpResponse(status=200)
|
||||
except:
|
||||
except DatabaseError:
|
||||
resp = HttpResponse(
|
||||
'{"error" : "could not create rotation!"}', status=400)
|
||||
|
||||
@@ -161,7 +158,7 @@ def create_rotation(request, *args, **kwargs):
|
||||
|
||||
@require_http_methods(["DELETE"])
|
||||
@ensure_csrf_cookie
|
||||
@login_required(login_url='/login')
|
||||
@login_required(login_url='/admin/login')
|
||||
@permission_required('infoscreen.delete_rotation', raise_exception=True)
|
||||
def delete_rotation(request, *args, **kwargs):
|
||||
"""Delete rotation."""
|
||||
@@ -171,7 +168,7 @@ def delete_rotation(request, *args, **kwargs):
|
||||
try:
|
||||
Rotation.objects.filter(id=id).delete()
|
||||
resp = HttpResponse(status=200)
|
||||
except:
|
||||
except DatabaseError:
|
||||
resp = HttpResponse(
|
||||
'{"error" : "could not delete rotation!"}', status=400)
|
||||
|
||||
@@ -182,7 +179,7 @@ createInstance = create_item_generator(InfoInstance)
|
||||
deleteInstance = delete_item_generator(InfoInstance)
|
||||
createABBItem = create_item_generator(ABBInfoItem)
|
||||
createSossoItem = create_item_generator(SossoInfoItem)
|
||||
createHslItem = create_item_generator(HslInfoItem)
|
||||
createLunchItem = create_item_generator(LunchItem)
|
||||
createExternalImageInfoItem = create_item_generator(ExternalImageInfoItem)
|
||||
createExternalWebsiteItem = create_item_generator(ExternalWebsiteInfoItem)
|
||||
createEventItem = create_item_generator(EventInfoItem)
|
||||
|
||||
@@ -2,13 +2,14 @@ from django.shortcuts import render
|
||||
from django.http import HttpResponse, JsonResponse, HttpResponseBadRequest
|
||||
from django.views.decorators.http import require_http_methods
|
||||
from django.conf import settings
|
||||
from django.db import DatabaseError
|
||||
|
||||
from infoscreen.models import Rotation, InfoItem, InfoInstance
|
||||
from infoscreen.hsl_fetcher import fetch as hsl_fetch
|
||||
|
||||
import json
|
||||
import logging
|
||||
import threading
|
||||
import requests
|
||||
|
||||
|
||||
@require_http_methods(["GET"])
|
||||
@@ -22,7 +23,7 @@ def default(request, *args, **kwargs):
|
||||
"""Try getting first rotation item."""
|
||||
try:
|
||||
first = Rotation.objects.all()[0].id
|
||||
except:
|
||||
except DatabaseError:
|
||||
first = 0
|
||||
return index(request, first, *args, **kwargs)
|
||||
|
||||
@@ -77,25 +78,3 @@ def info_items(request, *args, **kwargs):
|
||||
items.append(i.get_dict())
|
||||
|
||||
return JsonResponse(items, safe=False)
|
||||
|
||||
|
||||
@require_http_methods(["GET"])
|
||||
def hsl_timetable_settings(request, *args, **kwargs):
|
||||
"""Set HSL timetable settings."""
|
||||
d = {"departure_threshold": settings.HSL_DEPARTURE_THRESHOLD,
|
||||
"hurry_threshold": settings.HSL_HURRY_THRESHOLD}
|
||||
|
||||
return JsonResponse(d, status=200)
|
||||
|
||||
|
||||
@require_http_methods(["GET"])
|
||||
def CurrentHSLView(request, *args, **kwargs):
|
||||
"""Get HSL data and return it."""
|
||||
try:
|
||||
api_resp = hsl_fetch()
|
||||
except Exception as ex:
|
||||
logging.exception('Failed to fetch HSL timetables.')
|
||||
error = {'error': 'Aikataulujen haku epäonnistui.'}
|
||||
return JsonResponse(error, status=200)
|
||||
|
||||
return JsonResponse(api_resp, status=200, safe=False)
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
from django.contrib import admin
|
||||
from modeltranslation.admin import TranslationAdmin
|
||||
|
||||
from kaehmy.models import Application, Comment, CustomRole, PresetRole, TelegramChannel
|
||||
|
||||
admin.site.register(Application)
|
||||
admin.site.register(Comment)
|
||||
admin.site.register(CustomRole)
|
||||
admin.site.register(PresetRole, TranslationAdmin)
|
||||
admin.site.register(TelegramChannel)
|
||||