Merge branch 'develop' into feature-nobot
@@ -3,3 +3,5 @@ show_missing = True
|
||||
[run]
|
||||
omit =
|
||||
*/migrations/*
|
||||
*/admin.py
|
||||
*/translation.py
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
HOST=api.dev.sahkoinsinoorikilta.fi
|
||||
DEBUG=True
|
||||
SECRET_KEY=7p$85^4ibb^p4-=vs44b7!y0e-zemugze18@a#30&71=a8)dp(
|
||||
TG_BOT_TOKEN=
|
||||
EMAIL_HOST=
|
||||
EMAIL_PASSWD=
|
||||
DB_USER=postgres
|
||||
DB_PASSWD=postgres
|
||||
DB_HOST=db
|
||||
DB_PORT=5432
|
||||
@@ -0,0 +1,10 @@
|
||||
HOST=localhost
|
||||
DEBUG=True
|
||||
SECRET_KEY=7p$85^4ibb^p4-=vs44b7!y0e-zemugze18@a#30&71=a8)dp(
|
||||
TG_BOT_TOKEN=
|
||||
EMAIL_HOST=
|
||||
EMAIL_PASSWD=
|
||||
DB_USER=postgres
|
||||
DB_PASSWD=postgres
|
||||
DB_HOST=db
|
||||
DB_PORT=5432
|
||||
@@ -4,11 +4,10 @@
|
||||
"jquery": true
|
||||
},
|
||||
"globals": {
|
||||
"angular": 1,
|
||||
"noty": 1,
|
||||
"app": 1,
|
||||
"_": 1,
|
||||
"moment": 1
|
||||
"angular": true,
|
||||
"noty": true,
|
||||
"_": true,
|
||||
"moment": true
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"rules": {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
*.swp
|
||||
sikweb/settings.py
|
||||
.env
|
||||
*~
|
||||
*.pyc
|
||||
*.sqlite3
|
||||
@@ -10,7 +10,7 @@ members/logs/*
|
||||
logs/
|
||||
/media/
|
||||
node_modules/
|
||||
/.coverage
|
||||
.coverage
|
||||
db.sqlite3
|
||||
requirements_henu.txt
|
||||
/collected_static/
|
||||
|
||||
@@ -1,102 +1,117 @@
|
||||
stages:
|
||||
- test
|
||||
- setup
|
||||
- lint
|
||||
- test
|
||||
- publish
|
||||
- deploy
|
||||
|
||||
install:
|
||||
image: node:14
|
||||
stage: setup
|
||||
script:
|
||||
- npm ci
|
||||
artifacts:
|
||||
paths:
|
||||
- node_modules
|
||||
expire_in: 1 week
|
||||
|
||||
test:
|
||||
image: python:3.5
|
||||
image: python:3.7
|
||||
stage: test
|
||||
needs: []
|
||||
services:
|
||||
- postgres:latest
|
||||
- postgres:12
|
||||
variables:
|
||||
POSTGRES_DB: ci
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
DATABASE_URL: "postgresql://postgres:postgres@postgres:5432/$POSTGRES_DB"
|
||||
DB_HOST: postgres
|
||||
script:
|
||||
- python -V
|
||||
- pip install -r requirements.txt
|
||||
- cp sikweb/settings-sample.py sikweb/default_settings.py
|
||||
- cp sikweb/.ci-settings.py sikweb/settings.py
|
||||
- python manage.py migrate --noinput
|
||||
- python manage.py createdefaultadmin
|
||||
- python manage.py test
|
||||
|
||||
pycodestyle:
|
||||
image: python:3.5
|
||||
lint:py:
|
||||
image: python:3.7
|
||||
stage: lint
|
||||
needs: []
|
||||
script:
|
||||
- pip install pycodestyle
|
||||
- pycodestyle --config=setup.cfg --count .
|
||||
- pycodestyle --config=pycodestyle.cfg --count .
|
||||
|
||||
eslint:
|
||||
image: node:alpine
|
||||
lint:js:
|
||||
image: node:14
|
||||
stage: lint
|
||||
before_script:
|
||||
- npm install
|
||||
needs: ["install"]
|
||||
script:
|
||||
- npm run eslint
|
||||
- npm run lint:js
|
||||
|
||||
remark:
|
||||
image: node:alpine
|
||||
lint:md:
|
||||
image: node:14
|
||||
stage: lint
|
||||
before_script:
|
||||
- npm install
|
||||
needs: ["install"]
|
||||
script:
|
||||
- npm run remark
|
||||
- npm run lint:md
|
||||
|
||||
publish:
|
||||
stage: publish
|
||||
image: docker:stable
|
||||
needs: ["test", "lint:py", "lint:js", "lint:md"]
|
||||
services:
|
||||
- docker:stable-dind
|
||||
only:
|
||||
- develop
|
||||
- master
|
||||
script:
|
||||
- docker info
|
||||
- docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY
|
||||
- docker build . -t "$IMAGE_NAME"
|
||||
- docker push "$IMAGE_NAME"
|
||||
|
||||
deploy_dev:
|
||||
deploy:dev:
|
||||
stage: deploy
|
||||
image: alpine:latest
|
||||
environment:
|
||||
name: dev
|
||||
url: http://web.sik.party:8000
|
||||
image: docker:stable
|
||||
only:
|
||||
- develop
|
||||
before_script:
|
||||
- pwd
|
||||
- apk add --update openssh
|
||||
- ssh -V
|
||||
- mkdir -p ~/.ssh
|
||||
- echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
|
||||
- chmod 600 ~/.ssh/id_rsa
|
||||
- '[[ -f /.dockerenv ]] && echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config'
|
||||
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:
|
||||
stage: deploy
|
||||
image: alpine:latest
|
||||
environment:
|
||||
name: production
|
||||
url: https://sika.sahkoinsinoorikilta.fi
|
||||
when: manual
|
||||
name: dev
|
||||
url: http://api.dev.sahkoinsinoorikilta.fi
|
||||
variables:
|
||||
DOCKER_HOST: $DEV_CI_DOCKER_HOST
|
||||
DOCKER_TLS_VERIFY: 1
|
||||
before_script:
|
||||
- mkdir -p ~/.docker
|
||||
- echo "$DEV_TLSCACERT" > ~/.docker/ca.pem
|
||||
- echo "$DEV_TLSCERT" > ~/.docker/cert.pem
|
||||
- echo "$DEV_TLSKEY" > ~/.docker/key.pem
|
||||
- docker login -u gitlab-ci-token -p "$CI_BUILD_TOKEN" "$CI_REGISTRY"
|
||||
script:
|
||||
- docker stack deploy --with-registry-auth -c stack-compose-dev.yml "$SERVICE_NAME"
|
||||
after_script:
|
||||
- docker logout "$CI_REGISTRY"
|
||||
|
||||
deploy:production:
|
||||
stage: deploy
|
||||
image: docker:stable
|
||||
only:
|
||||
- master
|
||||
environment:
|
||||
name: production
|
||||
url: api.sahkoinsinoorikilta.fi
|
||||
when: manual
|
||||
variables:
|
||||
DOCKER_HOST: $CI_DOCKER_HOST
|
||||
DOCKER_TLS_VERIFY: 1
|
||||
before_script:
|
||||
- pwd
|
||||
- apk add --update openssh
|
||||
- ssh -V
|
||||
- mkdir -p ~/.ssh
|
||||
- echo "$SSH_PRIVATE_KEY" > ~/.ssh/id_rsa
|
||||
- chmod 600 ~/.ssh/id_rsa
|
||||
- echo -e "Host *\n\tStrictHostKeyChecking no\n\n" > ~/.ssh/config
|
||||
- mkdir -p ~/.docker
|
||||
- echo "$TLSCACERT" > ~/.docker/ca.pem
|
||||
- echo "$TLSCERT" > ~/.docker/cert.pem
|
||||
- echo "$TLSKEY" > ~/.docker/key.pem
|
||||
- docker login -u gitlab-ci-token -p "$CI_BUILD_TOKEN" "$CI_REGISTRY"
|
||||
script:
|
||||
- ssh $PROD_SSH_USER@$PROD_SSH_HOST "zsh ~/deploy.sh"
|
||||
- docker stack deploy --with-registry-auth -c stack-compose.yml "$SERVICE_NAME"
|
||||
after_script:
|
||||
- docker logout "$CI_REGISTRY"
|
||||
@@ -0,0 +1 @@
|
||||
_
|
||||
@@ -1,9 +1,10 @@
|
||||
#!/bin/bash
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
PURPLE='\033[0;35m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
. "${VIRTUAL_ENV}/bin/activate"
|
||||
source "${VIRTUAL_ENV}/bin/activate"
|
||||
|
||||
if [ $? -ne 0 ]
|
||||
then
|
||||
@@ -14,10 +15,8 @@ fi
|
||||
set -e
|
||||
|
||||
printf "${PURPLE}Running pre-push tests.${NC}\n"
|
||||
printf "${PURPLE}npm tests...${NC}\n"
|
||||
npm test
|
||||
printf "${PURPLE}pycodestyle tests...${NC}\n"
|
||||
pycodestyle .
|
||||
printf "${PURPLE}linters...${NC}\n"
|
||||
npm run lint
|
||||
printf "${PURPLE}unit tests...${NC}\n"
|
||||
python -Wall manage.py test --noinput
|
||||
set +e
|
||||
@@ -1 +1 @@
|
||||
3.6.8
|
||||
3.7.4
|
||||
|
||||
@@ -1,8 +1,20 @@
|
||||
FROM python:3.5
|
||||
FROM python:3.7-alpine
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
ENV IS_DOCKER 1
|
||||
RUN mkdir /code
|
||||
WORKDIR /code
|
||||
ADD requirements.txt /code/
|
||||
RUN env
|
||||
ADD . /code/
|
||||
WORKDIR /app
|
||||
COPY requirements.txt ./
|
||||
COPY requirements.production.txt ./
|
||||
COPY . ./
|
||||
|
||||
# uWSGI, gunicorn etc.
|
||||
RUN apk add --no-cache python3-dev build-base linux-headers pcre-dev openssl bash \
|
||||
# PSQL
|
||||
&& apk add --no-cache postgresql-dev \
|
||||
# Pillow
|
||||
&& apk add --no-cache jpeg-dev zlib-dev \
|
||||
&& pip install --upgrade pip \
|
||||
&& pip install -r requirements.txt \
|
||||
&& pip install -r requirements.production.txt
|
||||
|
||||
RUN python manage.py collectstatic --noinput
|
||||
|
||||
CMD ["sh", "-c", "./production_entrypoint.sh"]
|
||||
|
||||
@@ -1,52 +0,0 @@
|
||||
[[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"
|
||||
@@ -1,706 +0,0 @@
|
||||
{
|
||||
"_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"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
from django.contrib import admin
|
||||
|
||||
# Register your models here.
|
||||
@@ -1,3 +0,0 @@
|
||||
from django.db import models
|
||||
|
||||
# Create your models here.
|
||||
@@ -1,124 +0,0 @@
|
||||
body {
|
||||
background-color: white;
|
||||
font-family: monospace;
|
||||
color: black;
|
||||
}
|
||||
#container{
|
||||
position:relative;
|
||||
width:95%;
|
||||
margin-left:auto;
|
||||
margin-right:auto;
|
||||
height:100%;
|
||||
overflow:hidden;
|
||||
|
||||
}
|
||||
#upper{
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: bottom center;
|
||||
background-image: url("/static/coffee_scale/img/smokes.png");
|
||||
transform-origin: bottom;
|
||||
animation: smokes 8s ease-in-out 0s infinite;
|
||||
opacity:0;
|
||||
height:40%;
|
||||
}
|
||||
#lower{
|
||||
position:relative;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: top center;
|
||||
background-image: url("/static/coffee_scale/img/coffeecup3.png");
|
||||
height:60%;
|
||||
}
|
||||
#scale{
|
||||
position:absolute;
|
||||
top:80%;
|
||||
width:90%;
|
||||
height:10%;
|
||||
margin: 0% 5% 0% 5%;
|
||||
background: lightgrey;
|
||||
border-radius: 10px;
|
||||
overflow:hidden;
|
||||
}
|
||||
#scale2{
|
||||
width: 0%;
|
||||
transition: width 2s;
|
||||
height:100%;
|
||||
background: green;
|
||||
border-radius: 10px;
|
||||
}
|
||||
.brewtime{
|
||||
text-align:right;
|
||||
position:absolute;
|
||||
right:0px;
|
||||
z-index:5;
|
||||
font-size:10vw;
|
||||
}
|
||||
#address{
|
||||
text-align:left;
|
||||
position:absolute;
|
||||
left:0px;
|
||||
z-index:5;
|
||||
font-size:4vw;
|
||||
color: #333;
|
||||
}
|
||||
.layertwo{
|
||||
display: None;
|
||||
}
|
||||
noscript{
|
||||
color:red;
|
||||
}
|
||||
.text{
|
||||
color:green;
|
||||
position:absolute;
|
||||
top:50%;
|
||||
left:50%;
|
||||
}
|
||||
.brewing{
|
||||
animation: brewing 5s ease-in-out 0s infinite;
|
||||
}
|
||||
.hurry{
|
||||
color:red !important;
|
||||
}
|
||||
.unknown{
|
||||
color:orange !important;
|
||||
animation: unknown 5s ease-in-out 0s infinite;
|
||||
}
|
||||
.friday{
|
||||
animation: friday 20s ease-in-out 0s infinite;
|
||||
}
|
||||
.normal{
|
||||
animation: normal 1000s ease-in-out 0s infinite;
|
||||
}
|
||||
.coffeeready{
|
||||
animation: coffeeready 10s ease-in-out 0s;
|
||||
}
|
||||
@keyframes smokes {
|
||||
0% {transform: skewX(-10deg);}
|
||||
50% {transform: skewX(10deg);}
|
||||
100% {transform: skewX(-10deg);}
|
||||
}
|
||||
@keyframes brewing {
|
||||
0% {color:green;}
|
||||
50% {color: transparent;}
|
||||
100% {color:green;}
|
||||
}
|
||||
@keyframes coffeeready {
|
||||
0% {background-color:white;}
|
||||
25% {background-color:rgb(100, 255, 100);}
|
||||
50% {background-color:white;}
|
||||
75% {background-color:rgb(100, 255, 100);}
|
||||
100% {background-color:white;}
|
||||
}
|
||||
@keyframes unknown {
|
||||
0%,40% {transform: rotate(0deg);}
|
||||
60%,100% {transform: rotate(360deg);}
|
||||
}
|
||||
@keyframes friday {
|
||||
0% {transform: rotate(0deg);}
|
||||
100% {transform: rotate(360deg);}
|
||||
}
|
||||
@keyframes normal {
|
||||
0%,49% {transform: rotate(0deg);}
|
||||
50%,100% {transform: rotate(360deg);}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 9.0 KiB |
@@ -1,183 +0,0 @@
|
||||
//Inner state
|
||||
var lastBrew = new Date(0);
|
||||
var brewing = false;
|
||||
var backoff = 2000;
|
||||
|
||||
//MQTT client config
|
||||
var username = "coffee-user-"+ Math.random();
|
||||
// eslint-disable-next-line no-undef
|
||||
var client = new Paho.MQTT.Client("sika.sahkoinsinoorikilta.fi", 9001, username);
|
||||
client.onMessageArrived = function (message) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.log("Topic: "+message.destinationName+" msg: "+message.payloadString);
|
||||
var ev = new CustomEvent(message.destinationName, {'detail': message.payloadString});
|
||||
window.dispatchEvent(ev);
|
||||
}
|
||||
|
||||
function reconnect(responseObject){
|
||||
if (responseObject.errorCode !== 0) {
|
||||
console.log("connection lost! Reason: "+responseObject.errorMessage); // eslint-disable-line no-console
|
||||
setTimeout(function(){
|
||||
client.connect({onSuccess:onConnect, useSSL:true, onFailure: reconnect});
|
||||
}, backoff);
|
||||
}
|
||||
}
|
||||
|
||||
function onConnect() {
|
||||
console.log("MQTT connected"); // eslint-disable-line no-console
|
||||
//set and reset reconnector
|
||||
client.onConnectionLost = reconnect
|
||||
// subscribe to topics
|
||||
client.subscribe("sik/kiltahuone/kahvivaaka/cups");
|
||||
client.subscribe("sik/kiltahuone/kahvivaaka/brewing");
|
||||
client.subscribe("sik/kiltahuone/kahvivaaka/brewtime");
|
||||
}
|
||||
|
||||
// data update and parse functions
|
||||
function parseCups(ev){
|
||||
var cups = parseFloat(ev.detail).toFixed(1)
|
||||
|
||||
function makeEvent(cups) {
|
||||
return (String(cups) !== '-1.0')
|
||||
? new CustomEvent("cupsChanged", {'detail': cups})
|
||||
: new CustomEvent("cupsError", {'detail': 'Error: unable to fetch cups :('});
|
||||
}
|
||||
|
||||
window.dispatchEvent(makeEvent(cups));
|
||||
}
|
||||
function updateCups(ev){
|
||||
$("#text").text(ev.detail);
|
||||
}
|
||||
function showCupsError(ev) {
|
||||
$('#text').text(ev.detail);
|
||||
$('#text').css({
|
||||
'font-size': '7vh',
|
||||
'left': '0',
|
||||
'top': '40%',
|
||||
'width': '100%',
|
||||
'text-align': 'center',
|
||||
'color': 'red',
|
||||
});
|
||||
$('#lower').css({'background-image': 'none'});
|
||||
}
|
||||
function updateScale(ev){
|
||||
$("#scale2").css({width: Math.min(ev.detail/9*100,100) + '%'});
|
||||
}
|
||||
|
||||
function tick(){
|
||||
var ev = new CustomEvent("tick", {'detail': new Date()});
|
||||
window.dispatchEvent(ev);
|
||||
}
|
||||
|
||||
function updateTime(ev){
|
||||
var now = ev.detail;
|
||||
$("#time").html(formatTime(now.getHours(),now.getMinutes(),now.getSeconds()));
|
||||
}
|
||||
|
||||
function coffeeLowEffect(ev){
|
||||
ev.detail <= 2 ? $("#text").addClass("hurry") : $("#text").removeClass("hurry");
|
||||
}
|
||||
function coffeeReadyEffect(){
|
||||
$("body").addClass("coffeeready");
|
||||
// autoclear animation class in 10s
|
||||
setTimeout(function(){$("body").removeClass("coffeeready");}, 10000);
|
||||
}
|
||||
function hotEffect(ev){
|
||||
var opa = Math.max(100 - ev.detail / 90000,0);
|
||||
$("#upper").css({opacity: opa/100});
|
||||
}
|
||||
function brewAnimStart(){
|
||||
$(".text").addClass("brewing");
|
||||
$(".layerone").hide();
|
||||
$(".layertwo").show();
|
||||
}
|
||||
function brewAnimEnd(){
|
||||
$(".text").removeClass("brewing");
|
||||
$(".layertwo").hide();
|
||||
$(".layerone").show();
|
||||
}
|
||||
function brewNotifier(ev){
|
||||
var new_brewing = parseInt(ev.detail);
|
||||
if (new_brewing == 1 && brewing == 0){
|
||||
window.dispatchEvent(new Event("brewStart"));
|
||||
} else if (new_brewing == 0 && brewing == 1){
|
||||
window.dispatchEvent(new Event("brewEnd"));
|
||||
}
|
||||
brewing = new_brewing;
|
||||
}
|
||||
function brewTimeParser(ev){
|
||||
lastBrew = new Date(parseInt(ev.detail)*1000.0);
|
||||
}
|
||||
function updateBrewDiff(){
|
||||
var now = new Date();
|
||||
var timeDiff = Math.max(now.getTime() - lastBrew.getTime(), 0);
|
||||
var eve = new CustomEvent("dtUpdate", {'detail': timeDiff});
|
||||
window.dispatchEvent(eve);
|
||||
}
|
||||
function updateBrewTime(ev){
|
||||
var timeDiff = ev.detail;
|
||||
var timeStr;
|
||||
if (timeDiff < 3600000){
|
||||
timeStr = Math.round(timeDiff / 60000) + ' min'
|
||||
} else if (timeDiff < 10000* 3600 * 1000){ // 1000h
|
||||
timeStr = '~' + Math.round(timeDiff / 3600000 * 2) / 2 + ' h';
|
||||
} else {
|
||||
timeStr = "???"
|
||||
}
|
||||
$("#brewtime").html(timeStr);
|
||||
}
|
||||
|
||||
// Helpers
|
||||
|
||||
function nToS(num){
|
||||
return num < 10 ? "0" + num : "" + num;
|
||||
}
|
||||
|
||||
function formatTime(hours, minutes, seconds){
|
||||
return nToS(hours)+":"+nToS(minutes)+":"+nToS(seconds)
|
||||
}
|
||||
|
||||
function resize(){
|
||||
var w = $("#container").width();
|
||||
var h = $("#container").height();
|
||||
var s = w > h ? h : w;
|
||||
var font = s * 0.8 * 0.38/Math.sqrt(3);
|
||||
$(".text").css({ top: s*0.16-font/2 + 'px',
|
||||
fontSize: font + 'px',
|
||||
marginLeft: -font*3*3/10 + 'px'});
|
||||
}
|
||||
|
||||
// Init everything
|
||||
|
||||
$(document).ready(function(){
|
||||
client.connect({onSuccess:onConnect, useSSL:true, onFailure:reconnect});
|
||||
|
||||
//connect MQTT event listeners
|
||||
window.addEventListener("sik/kiltahuone/kahvivaaka/cups", parseCups);
|
||||
window.addEventListener("sik/kiltahuone/kahvivaaka/brewing", brewNotifier);
|
||||
window.addEventListener("sik/kiltahuone/kahvivaaka/brewtime", brewTimeParser);
|
||||
|
||||
//connect other event listeners
|
||||
window.addEventListener("cupsChanged", updateCups);
|
||||
window.addEventListener("cupsChanged", coffeeLowEffect);
|
||||
window.addEventListener("cupsChanged", updateScale);
|
||||
window.addEventListener("cupsChanged", resize);
|
||||
|
||||
window.addEventListener("cupsError", showCupsError);
|
||||
window.addEventListener("cupsError", coffeeLowEffect);
|
||||
window.addEventListener("cupsError", updateScale);
|
||||
|
||||
window.addEventListener("brewStart", brewAnimStart);
|
||||
window.addEventListener("brewEnd", brewAnimEnd);
|
||||
window.addEventListener("brewEnd", coffeeReadyEffect);
|
||||
window.addEventListener("tick", updateTime);
|
||||
window.addEventListener("tick", updateBrewDiff);
|
||||
window.addEventListener("dtUpdate", updateBrewTime);
|
||||
window.addEventListener("dtUpdate", hotEffect);
|
||||
|
||||
//start time based events
|
||||
setInterval(tick, 100);
|
||||
tick();
|
||||
|
||||
});
|
||||
$(window).resize(resize);
|
||||
@@ -1,41 +0,0 @@
|
||||
{% load i18n %}
|
||||
{% load static %}
|
||||
|
||||
<html>
|
||||
<head>
|
||||
<title>Coffee Cups @Guild Room - AYY SIK ry</title>
|
||||
<meta charset="UTF-8">
|
||||
<meta http-equiv="refresh" content="3600">
|
||||
<meta http-equiv="cache-control" content="max-age=0" />
|
||||
<meta http-equiv="cache-control" content="no-cache" />
|
||||
<meta http-equiv="expires" content="0" />
|
||||
<meta http-equiv="expires" content="Tue, 01 Jan 1980 1:00:00 GMT" />
|
||||
<meta http-equiv="pragma" content="no-cache" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<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 "coffee_scale/css/coffee.css" %}">
|
||||
<script src="{% static "coffee_scale/js/coffee.js" %}"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container">
|
||||
<span id="brewtime" class="brewtime layerone"></span>
|
||||
<span class="brewtime layertwo">:)</span>
|
||||
<span id="address">
|
||||
ka.dy.fi
|
||||
<noscript><br>This page uses JavaScript!</noscript>
|
||||
<br><span id="time"></span></span>
|
||||
</span>
|
||||
<div id="upper">
|
||||
</div>
|
||||
<!--Kahvinkeitin on rikki. Varakeittimellä keitettyä kahvia saattaa olla.-->
|
||||
<div id="lower" class="normal">
|
||||
<div id="text" class="text layerone">???</div>
|
||||
<div class="text layertwo"> +</div>
|
||||
<div id="scale"><div id="scale2"></div></div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,2 +0,0 @@
|
||||
from django.test import TestCase, Client
|
||||
from django.conf import settings
|
||||
@@ -1,12 +0,0 @@
|
||||
from django.conf.urls import url
|
||||
from django.conf import settings
|
||||
from .views import coffee_view
|
||||
|
||||
urlpatterns = [
|
||||
# landing page
|
||||
url(r'^$', coffee_view),
|
||||
]
|
||||
|
||||
if settings.DEBUG:
|
||||
from django.contrib.staticfiles.urls import staticfiles_urlpatterns
|
||||
urlpatterns += staticfiles_urlpatterns()
|
||||
@@ -1,11 +0,0 @@
|
||||
from django.shortcuts import render
|
||||
from django.http import JsonResponse
|
||||
|
||||
from django.utils import timezone
|
||||
|
||||
import logging
|
||||
from django.conf import settings
|
||||
|
||||
|
||||
def coffee_view(request):
|
||||
return render(request, 'coffee_scale:coffee.html')
|
||||
@@ -2,12 +2,24 @@ version: '3'
|
||||
|
||||
services:
|
||||
db:
|
||||
image: postgres
|
||||
image: postgres:12
|
||||
volumes:
|
||||
- dbdata:/var/lib/postgresql/data
|
||||
ports:
|
||||
- "5432:5432"
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=postgres
|
||||
|
||||
web:
|
||||
build: .
|
||||
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"]
|
||||
command: ["bash", "-c", "cd /app & bash setup.sh --no-input --no-npm && gunicorn -w 4 -b 0.0.0.0:8000 sikweb.wsgi"]
|
||||
env_file:
|
||||
- .env
|
||||
ports:
|
||||
- "8000:8000"
|
||||
depends_on:
|
||||
- db
|
||||
|
||||
volumes:
|
||||
dbdata:
|
||||
|
||||
@@ -56,7 +56,8 @@ app.filter('unsafe', function($sce) {
|
||||
app.controller('ABBController', function($scope, $http){
|
||||
$scope.jobs = [];
|
||||
var min_date = moment().subtract(30,'days').format("YYYY-MM-DD%20HH:mm:ss");
|
||||
var url = "https://sahkoinsinoorikilta.fi/api/news.php";
|
||||
// TODO: FIX, we try to get rid of php, not depend on it!
|
||||
var url = "https://old.sahkoinsinoorikilta.fi/api/news.php";
|
||||
var params = "?type=11&lang=fi&title_search=ABB&min_date="+min_date
|
||||
$http.get(url+params).then(function(response){
|
||||
$scope.jobs = _.filter(response.data, function(job){
|
||||
|
||||
@@ -5,15 +5,21 @@ from webapp.utils import month_from_now
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from auditlog.registry import auditlog
|
||||
from phonenumber_field.modelfields import PhoneNumberField
|
||||
|
||||
from webapp.models import BaseRole
|
||||
import logging
|
||||
|
||||
import webapp.models
|
||||
|
||||
# TODO: Move BaseRole to Kaehmt App; will fuck up the DB since table is removed, if no data migration is done before-hand.
|
||||
# Either reconstruct all kaehmy roles from scratch then, or do these migrations:
|
||||
# 1. Create table here
|
||||
# 2. Data migrate from webapp BaseRole to new kaehmy BaseRole
|
||||
# 3. Delete webapp BaseRole table
|
||||
|
||||
VERBOSE_NAME = _('Kaehmy')
|
||||
|
||||
|
||||
class KaehmyBaseRole(webapp.models.BaseRole):
|
||||
class KaehmyBaseRole(BaseRole):
|
||||
"""ABC"""
|
||||
|
||||
CATEGORIES = (
|
||||
('corporate', _('Corporate affairs')),
|
||||
|
||||
@@ -23,7 +23,7 @@
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
background-color: #052f5f;
|
||||
background-color: #0c2938;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 192 KiB After Width: | Height: | Size: 70 KiB |
@@ -1,5 +1,4 @@
|
||||
{% if wrap_label %}
|
||||
<label{% if widget.attrs.id %} for="{{ widget.attrs.id }}"{% endif %}>{% endif %}
|
||||
<label{% if widget.attrs.id %} for="{{ widget.attrs.id }}"{% endif %}>
|
||||
{% include "django/forms/widgets/input.html" %}
|
||||
{% if wrap_label %} {{ widget.label }}</label>{% endif %}
|
||||
{{ widget.label }}</label>
|
||||
<span class="fa fa-info-circle" data-toggle="tooltip" data-placement="right" title="{{ widget.description }}"></span>
|
||||
|
||||
@@ -2,6 +2,6 @@
|
||||
|
||||
<div class="kaehmy_header-content">
|
||||
<div class="kaehmy-banner logo">
|
||||
<a href="/kaehmy"><img class="kaehmy-banner-image" src="/static/img/kaehmy_banner.png" alt="Aalto-yliopiston Sähköinsinöörikilta ry"></a>
|
||||
<a href="/kaehmy"><img class="kaehmy-banner-image" src="/static/kaehmy/img/kaehmy_banner.png" alt="Aalto-yliopiston Sähköinsinöörikilta ry"></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -16,21 +16,23 @@
|
||||
{% blocktrans %}Kaehmykoneella voit ilmaista kiinnostuksesi toimia killassa ensi vuonna.
|
||||
Listassa on vastuualueittain sekä hallitus- että toimihenkilövirkoja.
|
||||
Koska lista ei ole koskaan täydellinen, voit myös ehdottaa ihan uutta toimenkuvaa.
|
||||
Jos sinulla on kysyttävää mistä tahansa virasta, kannattaa konsultoida <a href="/static/other/kahmyopas.pdf">kaehmyopasta</a>
|
||||
Jos sinulla on kysyttävää mistä tahansa virasta, kannattaa konsultoida <a href="https://static.sahkoinsinoorikilta.fi/uus_webi/kahmyopas.pdf">kaehmyopasta</a>
|
||||
tai olla yhteydessä kyseistä virkaa tänä vuonna toimittavaan henkilöön.{% endblocktrans %}
|
||||
</p>
|
||||
<p>
|
||||
{% blocktrans %}Muista, että kaehmyn lähettäminen on kiinnostuksen ilmaus
|
||||
{% blocktrans %}(HUOM! Kaehmytekstin maksimipituus on 300 merkkiä. Tarvittaessa voit kirjoittaa lisätietoja kommenteihin.){% endblocktrans %}
|
||||
</p>
|
||||
<p>
|
||||
{% blocktrans %}Muista, että kaehmyn lähettäminen on kiinnostuksen ilmaus
|
||||
eikä siis missään nimessä sitova ilmoittautumien mihinkään tehtävään!{% endblocktrans %}
|
||||
</p>
|
||||
<h5>{% trans "Päivämääriä & deadlineja" %}</h5>
|
||||
<ul>
|
||||
<li><strong>29.10.</strong> {% blocktrans %}Hallitustyrkkypaneeli (haku hallitukseen olisi hyvä tehdä ennen tätä!){% endblocktrans %}</li>
|
||||
<li><strong>5.11.</strong> {% blocktrans %}Vaalikokous, osa 1 (puheenjohtajan valinta){% endblocktrans %}</li>
|
||||
<li><strong>12.11.</strong> {% blocktrans %}Kiltailta{% endblocktrans %}</li>
|
||||
<li><strong>15.11.</strong> {% blocktrans %}Vaalikokous, osa 2 (hallituksen valinta){% endblocktrans %}</li>
|
||||
<li><strong>20.11.</strong> {% blocktrans %}Haku toimariksi olisi hyvä tehdä ennen tätä!{% endblocktrans %}</li>
|
||||
<li><strong>26.11.</strong> {% blocktrans %}Vaalikokous, osa 3 (toimarien valinta){% endblocktrans %}</li>
|
||||
<li><strong>05.11.</strong> {% blocktrans %}Hallitustyrkkypaneeli{% endblocktrans %}</li>
|
||||
<li><strong>12.11.</strong> {% blocktrans %}Vaalikokous, osa 1 (puheenjohtajan valinta){% endblocktrans %}</li>
|
||||
<li><strong>19.11.</strong> {% blocktrans %}Toimikunta-appro{% endblocktrans %}</li>
|
||||
<li><strong>23.11.</strong> {% blocktrans %}Vaalikokous, osa 2 (hallituksen valinta){% endblocktrans %}</li>
|
||||
<li><strong>07.12.</strong> {% blocktrans %}Vaalikokous, osa 3 (toimarien valinta){% endblocktrans %}</li>
|
||||
</ul>
|
||||
<form name="kaehmyForm" action="/kaehmy/submit/" method="post" class="form">{% csrf_token %}
|
||||
{% bootstrap_field form.name %}
|
||||
@@ -46,7 +48,7 @@
|
||||
{{ preset_field.label }}
|
||||
</div>
|
||||
<div class="card-block">
|
||||
{% bootstrap_field preset_field show_label=False %}
|
||||
{% bootstrap_field preset_field show_label=False %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
@@ -59,11 +61,11 @@
|
||||
{{ custom_field.label }}
|
||||
</div>
|
||||
<div class="card-block">
|
||||
{% bootstrap_field custom_field show_label=False %}
|
||||
{% bootstrap_field custom_field show_label=False %}
|
||||
</div>
|
||||
</div>
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
{% endfor %}
|
||||
<div class="card">
|
||||
<div class="card-block">
|
||||
{% bootstrap_field form.custom_role_name %}
|
||||
@@ -71,7 +73,7 @@
|
||||
</div>
|
||||
</div>
|
||||
{% bootstrap_field form.text %}
|
||||
|
||||
|
||||
<input type="checkbox" required name="gdpr" value="1">
|
||||
<span>{% blocktrans %}
|
||||
Hyväksyn <a href="https://sik.ayy.fi/files/official/Tietosuojaseloste%20%E2%80%93%20Toimihenkil%C3%B6ksi%20hakemisen%20rekisteri.pdf" target="_blank">tietosuojaselosteen</a> ja tietojeni tallentamisen.
|
||||
|
||||
@@ -6,11 +6,11 @@ from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.contrib.auth.decorators import permission_required, login_required
|
||||
from django.conf import settings
|
||||
from django.core.mail import send_mail
|
||||
|
||||
import logging
|
||||
import requests
|
||||
from dealer.git import git
|
||||
from sikweb.settings import URL
|
||||
|
||||
from members.views.utils import *
|
||||
from kaehmy.models import Application, CustomRole, PresetRole, TelegramChannel
|
||||
@@ -60,12 +60,12 @@ def comment(request, *args, **kwargs):
|
||||
name = comment.name
|
||||
|
||||
subject = 'Kaehmyysi tai kommenttiisi on vastattu!'
|
||||
body = ('{} on vastannut kaehmyhakemukseesi tai kommenttiisi kaehmypalvelussa.\r\n\r\n'
|
||||
'Käy lukemassa viesti osoitteessa http://sika.sahkoinsinoorikilta.fi/kaehmy').format(name.capitalize())
|
||||
body = (f'{name.capitalize()} on vastannut kaehmyhakemukseesi tai kommenttiisi kaehmypalvelussa.\r\n\r\n'
|
||||
'Käy lukemassa viesti osoitteessa https://{URL}/kaehmy')
|
||||
|
||||
send_email(email, subject, body)
|
||||
logging.debug(
|
||||
'Sent kaehmy comment email to recipient <{}>'.format(email))
|
||||
f'Sent kaehmy comment email to recipient <{email}>')
|
||||
|
||||
return redirect('/kaehmy')
|
||||
else:
|
||||
@@ -123,7 +123,7 @@ def submit(request, *args, **kwargs):
|
||||
custom_role.save()
|
||||
application.custom_roles.add(custom_role)
|
||||
|
||||
url = 'https://sika.sahkoinsinoorikilta.fi/kaehmy'
|
||||
url = f'https://{URL}/kaehmy'
|
||||
|
||||
email = form.cleaned_data.get('email', '')
|
||||
name = form.cleaned_data.get('name', 'Anonymous')
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-03-26 17:32+0200\n"
|
||||
"POT-Creation-Date: 2021-01-18 21:36+0200\n"
|
||||
"PO-Revision-Date: 2017-11-02 23:09+0200\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
@@ -37,7 +37,7 @@ msgstr "Sössö articles"
|
||||
msgid "Today's lunch"
|
||||
msgstr ""
|
||||
|
||||
#: infoscreen/models.py:212 webapp/models.py:74
|
||||
#: infoscreen/models.py:212 webapp/models.py:70
|
||||
msgid "Events"
|
||||
msgstr "Events"
|
||||
|
||||
@@ -112,8 +112,8 @@ msgstr "Preview"
|
||||
msgid "Delete"
|
||||
msgstr "Delete"
|
||||
|
||||
#: infoscreen/templates/tabs/add_remove.html:23 kaehmy/models.py:56
|
||||
#: kaehmy/templates/list.html:36 webapp/models.py:125 webapp/models.py:154
|
||||
#: infoscreen/templates/tabs/add_remove.html:23 kaehmy/models.py:62
|
||||
#: kaehmy/templates/list.html:36 webapp/models.py:144 webapp/models.py:173
|
||||
msgid "Name"
|
||||
msgstr "Name"
|
||||
|
||||
@@ -189,7 +189,7 @@ msgstr "Phone number (not public)"
|
||||
msgid "Custom roles"
|
||||
msgstr "Custom roles"
|
||||
|
||||
#: kaehmy/forms.py:49 kaehmy/templates/kaehmy.html:41
|
||||
#: kaehmy/forms.py:49 kaehmy/templates/kaehmy.html:43
|
||||
msgid "Preset roles"
|
||||
msgstr "Preset roles"
|
||||
|
||||
@@ -201,157 +201,157 @@ msgstr "Invalid phone number"
|
||||
msgid "Custom role with the same name already exists."
|
||||
msgstr "Custom role with the same name already exists."
|
||||
|
||||
#: kaehmy/models.py:13
|
||||
#: kaehmy/models.py:18
|
||||
msgid "Kaehmy"
|
||||
msgstr "Kaehmy"
|
||||
|
||||
#: kaehmy/models.py:19
|
||||
#: kaehmy/models.py:25
|
||||
msgid "Corporate affairs"
|
||||
msgstr "Corporate affairs"
|
||||
|
||||
#: kaehmy/models.py:20 webapp/templates/freshmen.html:10
|
||||
#: kaehmy/models.py:26 webapp/templates/freshmen.html:10
|
||||
#: webapp/templates/navigation.html:8
|
||||
msgid "Freshmen"
|
||||
msgstr "Freshmen"
|
||||
|
||||
#: kaehmy/models.py:21 webapp/templates/international.html:10
|
||||
#: kaehmy/models.py:27 webapp/templates/international.html:10
|
||||
#: webapp/templates/navigation.html:14
|
||||
msgid "International"
|
||||
msgstr "International"
|
||||
|
||||
#: kaehmy/models.py:22
|
||||
#: kaehmy/models.py:28
|
||||
msgid "External affairs"
|
||||
msgstr "External affairs"
|
||||
|
||||
#: kaehmy/models.py:23
|
||||
#: kaehmy/models.py:29
|
||||
msgid "Media"
|
||||
msgstr ""
|
||||
|
||||
#: kaehmy/models.py:24
|
||||
#: kaehmy/models.py:30
|
||||
msgid "Technology"
|
||||
msgstr ""
|
||||
|
||||
#: kaehmy/models.py:25
|
||||
#: kaehmy/models.py:31
|
||||
msgid "Wellbeing"
|
||||
msgstr ""
|
||||
|
||||
#: kaehmy/models.py:26
|
||||
#: kaehmy/models.py:32
|
||||
msgid "Elepaja"
|
||||
msgstr ""
|
||||
|
||||
#: kaehmy/models.py:27
|
||||
#: kaehmy/models.py:33
|
||||
msgid "Ceremonies"
|
||||
msgstr ""
|
||||
|
||||
#: kaehmy/models.py:28
|
||||
#: kaehmy/models.py:34
|
||||
msgid "Studies"
|
||||
msgstr ""
|
||||
|
||||
#: kaehmy/models.py:29
|
||||
#: kaehmy/models.py:35
|
||||
msgid "Sössö magazine"
|
||||
msgstr "Sössö magazine"
|
||||
|
||||
#: kaehmy/models.py:30
|
||||
#: kaehmy/models.py:36
|
||||
msgid "Alumni relations"
|
||||
msgstr "Alumni relations"
|
||||
|
||||
#: kaehmy/models.py:31
|
||||
#: kaehmy/models.py:37
|
||||
msgid "Others"
|
||||
msgstr ""
|
||||
|
||||
#: kaehmy/models.py:33
|
||||
#: kaehmy/models.py:39
|
||||
msgid "Category"
|
||||
msgstr ""
|
||||
|
||||
#: kaehmy/models.py:39 webapp/models.py:136
|
||||
#: kaehmy/models.py:45
|
||||
msgid "Description"
|
||||
msgstr "Description"
|
||||
|
||||
#: kaehmy/models.py:42
|
||||
#: kaehmy/models.py:48
|
||||
msgid "Preset kaehmy role"
|
||||
msgstr "Preset kaehmy role"
|
||||
|
||||
#: kaehmy/models.py:43
|
||||
#: kaehmy/models.py:49
|
||||
msgid "Preset kaehmy roles"
|
||||
msgstr "Preset kaehmy roles"
|
||||
|
||||
#: kaehmy/models.py:50
|
||||
#: kaehmy/models.py:56
|
||||
msgid "Custom kaehmy role"
|
||||
msgstr "Custom kaehmy role"
|
||||
|
||||
#: kaehmy/models.py:51
|
||||
#: kaehmy/models.py:57
|
||||
msgid "Custom kaehmy roles"
|
||||
msgstr "Custom kaehmy roles"
|
||||
|
||||
#: kaehmy/models.py:57 kaehmy/templates/list.html:40 members/models.py:15
|
||||
#: kaehmy/models.py:63 kaehmy/templates/list.html:40 members/models.py:14
|
||||
msgid "Email"
|
||||
msgstr "Email"
|
||||
|
||||
#: kaehmy/models.py:58
|
||||
#: kaehmy/models.py:64
|
||||
msgid "Timestamp"
|
||||
msgstr ""
|
||||
|
||||
#: kaehmy/models.py:72
|
||||
#: kaehmy/models.py:78
|
||||
msgid "Kaehmykommentti"
|
||||
msgstr "Kaehmy comment"
|
||||
|
||||
#: kaehmy/models.py:73
|
||||
#: kaehmy/models.py:79
|
||||
msgid "Kaehmykommentit"
|
||||
msgstr "Kaehmy comments"
|
||||
|
||||
#: kaehmy/models.py:75 ohlhafv/models.py:36
|
||||
#: kaehmy/models.py:81 ohlhafv/models.py:36
|
||||
msgid "Message"
|
||||
msgstr ""
|
||||
|
||||
#: kaehmy/models.py:94 kaehmy/templates/kaehmy.html:12
|
||||
#: kaehmy/models.py:100 kaehmy/templates/kaehmy.html:12
|
||||
msgid "Kaehmylomake"
|
||||
msgstr "Kaehmy application"
|
||||
|
||||
#: kaehmy/models.py:95
|
||||
#: kaehmy/models.py:101
|
||||
msgid "Kaehmylomakkeet"
|
||||
msgstr "Kaehmy applications"
|
||||
|
||||
#: kaehmy/models.py:98 webapp/models.py:189
|
||||
#: kaehmy/models.py:104
|
||||
msgid "Phone number"
|
||||
msgstr ""
|
||||
|
||||
#: kaehmy/models.py:99
|
||||
#: kaehmy/models.py:105
|
||||
msgid "Year"
|
||||
msgstr ""
|
||||
|
||||
#: kaehmy/models.py:100
|
||||
#: kaehmy/models.py:106
|
||||
msgid "Text"
|
||||
msgstr ""
|
||||
|
||||
#: kaehmy/models.py:102
|
||||
#: kaehmy/models.py:108
|
||||
msgid "Custom role name"
|
||||
msgstr ""
|
||||
|
||||
#: kaehmy/models.py:104 webapp/models.py:126
|
||||
#: kaehmy/models.py:110 webapp/models.py:174
|
||||
msgid "Board member"
|
||||
msgstr "Board member"
|
||||
|
||||
#: kaehmy/models.py:112
|
||||
#: kaehmy/models.py:118
|
||||
msgid "Kaehmy application: {}"
|
||||
msgstr "Kaehmy application: {}"
|
||||
|
||||
#: kaehmy/models.py:134
|
||||
#: kaehmy/models.py:140
|
||||
msgid "Board: {}"
|
||||
msgstr ""
|
||||
|
||||
#: kaehmy/models.py:140
|
||||
#: kaehmy/models.py:146
|
||||
msgid "Official: {}"
|
||||
msgstr ""
|
||||
|
||||
#: kaehmy/models.py:157
|
||||
#: kaehmy/models.py:163
|
||||
msgid "Telegram channel"
|
||||
msgstr ""
|
||||
|
||||
#: kaehmy/models.py:158
|
||||
#: kaehmy/models.py:164
|
||||
msgid "Telegram channels"
|
||||
msgstr ""
|
||||
|
||||
#: kaehmy/tables.py:13 webapp/models.py:173
|
||||
#: kaehmy/tables.py:13
|
||||
msgid "Roles"
|
||||
msgstr ""
|
||||
|
||||
@@ -392,7 +392,8 @@ msgid ""
|
||||
" Koska lista ei ole koskaan täydellinen, voit myös ehdottaa ihan "
|
||||
"uutta toimenkuvaa.\n"
|
||||
" Jos sinulla on kysyttävää mistä tahansa virasta, kannattaa "
|
||||
"konsultoida <a href=\"/static/other/kahmyopas.pdf\">kaehmyopasta</a> \n"
|
||||
"konsultoida <a href=\"https://static.sahkoinsinoorikilta.fi/uus_webi/"
|
||||
"kahmyopas.pdf\">kaehmyopasta</a>\n"
|
||||
" tai olla yhteydessä kyseistä virkaa tänä vuonna toimittavaan "
|
||||
"henkilöön."
|
||||
msgstr ""
|
||||
@@ -406,42 +407,46 @@ msgstr ""
|
||||
|
||||
#: kaehmy/templates/kaehmy.html:23
|
||||
msgid ""
|
||||
"Muista, että kaehmyn lähettäminen on kiinnostuksen ilmaus \n"
|
||||
"(HUOM! Kaehmytekstin maksimipituus on 300 merkkiä. Tarvittaessa voit "
|
||||
"kirjoittaa lisätietoja kommenteihin.)"
|
||||
msgstr ""
|
||||
"(NOTE! The application text is limited to 300 characters. You can use the "
|
||||
"comment section for additional info.)"
|
||||
|
||||
#: kaehmy/templates/kaehmy.html:26
|
||||
msgid ""
|
||||
"Muista, että kaehmyn lähettäminen on kiinnostuksen ilmaus\n"
|
||||
" eikä siis missään nimessä sitova ilmoittautumien mihinkään "
|
||||
"tehtävään!"
|
||||
msgstr ""
|
||||
"Note, that sending an application is not binding and should be considered as "
|
||||
"a gesture of interest."
|
||||
|
||||
#: kaehmy/templates/kaehmy.html:26
|
||||
#: kaehmy/templates/kaehmy.html:29
|
||||
msgid "Päivämääriä & deadlineja"
|
||||
msgstr "Dates and deadlines"
|
||||
|
||||
#: kaehmy/templates/kaehmy.html:28
|
||||
msgid "Hallitustyrkkypaneeli (haku hallitukseen olisi hyvä tehdä ennen tätä!)"
|
||||
msgstr "Board panel discussion (applications to the board before this date!)"
|
||||
#: kaehmy/templates/kaehmy.html:31
|
||||
msgid "Hallitustyrkkypaneeli"
|
||||
msgstr "Panel for board applicants"
|
||||
|
||||
#: kaehmy/templates/kaehmy.html:29
|
||||
#: kaehmy/templates/kaehmy.html:32
|
||||
msgid "Vaalikokous, osa 1 (puheenjohtajan valinta)"
|
||||
msgstr "Election meeting, part 1 (chairman election)"
|
||||
|
||||
#: kaehmy/templates/kaehmy.html:30
|
||||
msgid "Kiltailta"
|
||||
msgstr "Guild night"
|
||||
#: kaehmy/templates/kaehmy.html:33
|
||||
msgid "Toimikunta-appro"
|
||||
msgstr "Guild committee crawl"
|
||||
|
||||
#: kaehmy/templates/kaehmy.html:31
|
||||
#: kaehmy/templates/kaehmy.html:34
|
||||
msgid "Vaalikokous, osa 2 (hallituksen valinta)"
|
||||
msgstr "Election meeting, part 2 (board election)"
|
||||
|
||||
#: kaehmy/templates/kaehmy.html:32
|
||||
msgid "Haku toimariksi olisi hyvä tehdä ennen tätä!"
|
||||
msgstr "Deadline to apply as a non-board official!"
|
||||
|
||||
#: kaehmy/templates/kaehmy.html:33
|
||||
#: kaehmy/templates/kaehmy.html:35
|
||||
msgid "Vaalikokous, osa 3 (toimarien valinta)"
|
||||
msgstr "Election meeting, part 3 (non-board election)"
|
||||
|
||||
#: kaehmy/templates/kaehmy.html:76
|
||||
#: kaehmy/templates/kaehmy.html:78
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
@@ -458,7 +463,7 @@ msgstr ""
|
||||
"of personal data.\n"
|
||||
" "
|
||||
|
||||
#: kaehmy/templates/kaehmy.html:82 members/templates/settings.html:23
|
||||
#: kaehmy/templates/kaehmy.html:84 members/templates/settings.html:23
|
||||
msgid "Submit"
|
||||
msgstr "Submit"
|
||||
|
||||
@@ -512,7 +517,7 @@ msgstr "New application"
|
||||
msgid "Statistics"
|
||||
msgstr ""
|
||||
|
||||
#: members/forms.py:107 members/models.py:102 members/tables.py:41
|
||||
#: members/forms.py:107 members/models.py:101 members/tables.py:41
|
||||
msgid "Member"
|
||||
msgstr "Member"
|
||||
|
||||
@@ -524,52 +529,52 @@ msgstr "I'm a member of AYY"
|
||||
msgid "I want to receive a weekly newsletter"
|
||||
msgstr "I want to receive a weekly newsletter"
|
||||
|
||||
#: members/models.py:13
|
||||
#: members/models.py:12
|
||||
msgid "First name"
|
||||
msgstr "First name"
|
||||
|
||||
#: members/models.py:14
|
||||
#: members/models.py:13
|
||||
msgid "Last name"
|
||||
msgstr "Last name"
|
||||
|
||||
#: members/models.py:16
|
||||
#: members/models.py:15
|
||||
msgid "Place of residence"
|
||||
msgstr "Place of residence"
|
||||
|
||||
#: members/models.py:18 members/models.py:69
|
||||
#: members/models.py:17 members/models.py:68
|
||||
#: members/templates/member_add_many.html:39
|
||||
msgid "AYY"
|
||||
msgstr "AYY"
|
||||
|
||||
#: members/models.py:19
|
||||
#: members/models.py:18
|
||||
msgid "JAS"
|
||||
msgstr "JAS"
|
||||
|
||||
#: members/models.py:50
|
||||
#: members/models.py:49
|
||||
msgid "Submitted"
|
||||
msgstr "Submitted"
|
||||
|
||||
#: members/models.py:67
|
||||
#: members/models.py:66
|
||||
msgid "Date"
|
||||
msgstr "Date"
|
||||
|
||||
#: members/models.py:68
|
||||
#: members/models.py:67
|
||||
msgid "Source"
|
||||
msgstr "Source"
|
||||
|
||||
#: members/models.py:70
|
||||
#: members/models.py:69
|
||||
msgid "Cash"
|
||||
msgstr "Cash"
|
||||
|
||||
#: members/models.py:71 members/templates/member_add_many.html:40
|
||||
#: members/models.py:70 members/templates/member_add_many.html:40
|
||||
msgid "Bank transfer"
|
||||
msgstr "Bank transfer"
|
||||
|
||||
#: members/models.py:95
|
||||
#: members/models.py:94
|
||||
msgid "Created"
|
||||
msgstr "Created"
|
||||
|
||||
#: members/models.py:103 members/templates/base.html:53
|
||||
#: members/models.py:102 members/templates/base.html:53
|
||||
#: members/templates/member_add_many_confirm.html:12
|
||||
msgid "Members"
|
||||
msgstr "Members"
|
||||
@@ -634,6 +639,14 @@ msgid "Hienoa! Jäsenhakemuksesi on nyt lähetetty."
|
||||
msgstr "Amazing! Your membership application has been sent."
|
||||
|
||||
#: members/templates/application_success.html:9
|
||||
msgid ""
|
||||
"Vahvistusviesti on lähetetty sähköpostiisi. Ota yhteyttä sik-vtmk@list.ayy."
|
||||
"fi jos viestiä ei näy."
|
||||
msgstr ""
|
||||
"Confirmation email is sent to given email address. Contact sik-vtmk@list.ayy."
|
||||
"fi if you didn't receive it."
|
||||
|
||||
#: members/templates/application_success.html:10
|
||||
msgid "Takaisin Sähköinsinöörikillan web-sivuille"
|
||||
msgstr "Back to the front page"
|
||||
|
||||
@@ -687,6 +700,103 @@ msgstr "Application form"
|
||||
msgid "Settings"
|
||||
msgstr "Settings"
|
||||
|
||||
#: members/templates/email_application_accept.html:2
|
||||
msgid "Moi"
|
||||
msgstr "Hi"
|
||||
|
||||
#: members/templates/email_application_accept.html:4
|
||||
msgid "Onnittelut! Sinut on hyväksytty Sähköinsinöörikillan jäseneksi."
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/email_application_accept.html:6
|
||||
msgid "Käy kurkkaamassa killan nettisivuilta"
|
||||
msgstr "Also go and check other challenges at"
|
||||
|
||||
#: members/templates/email_application_accept.html:6
|
||||
msgid ""
|
||||
"tulevia tapahtumia ja piipahda kiltahuoneella tutustumassa uusiin "
|
||||
"kiltatovereihisi!"
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/email_application_accept.html:8
|
||||
msgid "Liity myös killan TG-kanaville"
|
||||
msgstr "Join Guild's Telegram channels"
|
||||
|
||||
#: members/templates/email_application_accept.html:9
|
||||
msgid "SIK"
|
||||
msgstr "SIK"
|
||||
|
||||
#: members/templates/email_application_accept.html:10
|
||||
msgid "SIK-fuksit 2019"
|
||||
msgstr "SIK Freshmen 2019"
|
||||
|
||||
#: members/templates/email_application_accept.html:11
|
||||
msgid "SIK-fuksit 2019 -tiedotuskanava"
|
||||
msgstr "SIK Freshmen 2019 Notification channel"
|
||||
|
||||
#: members/templates/email_application_submit.html:2
|
||||
#: ohlhafv/templates/email.html:2
|
||||
msgid "Moikka"
|
||||
msgstr "Hi"
|
||||
|
||||
#: members/templates/email_application_submit.html:4
|
||||
msgid ""
|
||||
"Sait tämän viestin, sillä olet lähettänyt hakemuksen Aalto-yliopiston "
|
||||
"Sähköinsinöörikillan jäseneksi alla olevin tiedoin. Siistiä!"
|
||||
msgstr ""
|
||||
"You received this email, since you sent a membership application to the "
|
||||
"Guild of Electrical Engineering. That's so cool!"
|
||||
|
||||
#: members/templates/email_application_submit.html:6
|
||||
msgid "Etunimi"
|
||||
msgstr "First name"
|
||||
|
||||
#: members/templates/email_application_submit.html:7
|
||||
msgid "Sukunimi"
|
||||
msgstr "Last name"
|
||||
|
||||
#: members/templates/email_application_submit.html:8
|
||||
msgid "Sähköposti"
|
||||
msgstr "Email"
|
||||
|
||||
#: members/templates/email_application_submit.html:9
|
||||
msgid "Kotipaikkakunta"
|
||||
msgstr "Place of origin"
|
||||
|
||||
#: members/templates/email_application_submit.html:10
|
||||
msgid "AYY:n jäsen"
|
||||
msgstr "Member of AYY"
|
||||
|
||||
#: members/templates/email_application_submit.html:11
|
||||
msgid "Haluan jäsenmailin"
|
||||
msgstr "I want to receive weekly member email"
|
||||
|
||||
#: members/templates/email_application_submit.html:13
|
||||
msgid ""
|
||||
"Saat sähköpostiisi tiedon, kun sinut on hallituksen kokouksessa hyväksytty "
|
||||
"jäseneksi"
|
||||
msgstr "You will be notified via email once your application has been accepted"
|
||||
|
||||
#: members/templates/email_application_submit.html:15
|
||||
msgid "Muistathan maksaa jäsenmaksun! Alla maksutiedot"
|
||||
msgstr "Don't forget to pay your membership fee!"
|
||||
|
||||
#: members/templates/email_application_submit.html:17
|
||||
msgid "Saaja"
|
||||
msgstr "Recepient"
|
||||
|
||||
#: members/templates/email_application_submit.html:18
|
||||
msgid "Tilinumero"
|
||||
msgstr "Account number"
|
||||
|
||||
#: members/templates/email_application_submit.html:20
|
||||
msgid "Viite"
|
||||
msgstr "Reference Number"
|
||||
|
||||
#: members/templates/email_application_submit.html:21
|
||||
msgid "Summa"
|
||||
msgstr "Amount"
|
||||
|
||||
#: members/templates/member_add.html:15 members/templates/member_edit.html:18
|
||||
#: members/templates/payment_add.html:20 members/templates/payment_edit.html:18
|
||||
msgid "Save"
|
||||
@@ -804,95 +914,111 @@ msgstr "Payments in register:"
|
||||
msgid "Language"
|
||||
msgstr "Language"
|
||||
|
||||
#: members/templates/settings.html:20 sikweb/base.py:255
|
||||
#: members/templates/settings.html:20 sikweb/base.py:217
|
||||
msgid "Finnish"
|
||||
msgstr "Finnish"
|
||||
|
||||
#: members/templates/settings.html:21 sikweb/base.py:256
|
||||
#: members/templates/settings.html:21 sikweb/base.py:218
|
||||
msgid "English"
|
||||
msgstr "English"
|
||||
|
||||
#: members/views/applications.py:51 members/views/applications.py:112
|
||||
#: members/views/applications.py:137
|
||||
#: members/views/applications.py:53 members/views/applications.py:124
|
||||
#: members/views/applications.py:149
|
||||
msgid "No application id specified"
|
||||
msgstr "No application id specified"
|
||||
|
||||
#: members/views/applications.py:71
|
||||
#: members/views/applications.py:73
|
||||
msgid "Application missing 'id' field."
|
||||
msgstr "Application missing 'id' field."
|
||||
|
||||
#: members/views/applications.py:80
|
||||
#: members/views/applications.py:82
|
||||
msgid "Email {} is already in use by a member. Application cannot be accepted."
|
||||
msgstr ""
|
||||
"Email {} is already in use by a member. Application cannot be accepted."
|
||||
|
||||
#: members/views/applications.py:91
|
||||
#: members/views/applications.py:93
|
||||
msgid "Successfully accepted application"
|
||||
msgstr "Successfully accepted application"
|
||||
|
||||
#: members/views/applications.py:116
|
||||
#: members/views/applications.py:96
|
||||
msgid "Jäsenhakemuksesi Sähköinsinöörikiltaan on hyväksytty!"
|
||||
msgstr "Your membership application has been approved!"
|
||||
|
||||
#: members/views/applications.py:128
|
||||
msgid "Successfully deleted application"
|
||||
msgstr "Successfully deleted application"
|
||||
|
||||
#: members/views/applications.py:126
|
||||
#: members/views/applications.py:138
|
||||
msgid "Could not delete application object"
|
||||
msgstr "Could not delete application object"
|
||||
|
||||
#: members/views/members.py:86 members/views/members.py:188
|
||||
#: members/views/members.py:212
|
||||
#: members/views/applications.py:176
|
||||
msgid "Jäsenhakemuksesi Sähköinsinöörikiltaan on lähetetty onnistuneesti!"
|
||||
msgstr "Your membership application was sent successfully!"
|
||||
|
||||
#: members/views/applications.py:181 members/views/applications.py:182
|
||||
msgid "Kyllä"
|
||||
msgstr "Yes"
|
||||
|
||||
#: members/views/applications.py:181 members/views/applications.py:182
|
||||
msgid "Ei"
|
||||
msgstr "No"
|
||||
|
||||
#: members/views/members.py:85 members/views/members.py:187
|
||||
#: members/views/members.py:211
|
||||
msgid "No member id specified"
|
||||
msgstr "No member id specified"
|
||||
|
||||
#: members/views/members.py:127
|
||||
#: members/views/members.py:126
|
||||
msgid "Failed to import members"
|
||||
msgstr "Failed to import members"
|
||||
|
||||
#: members/views/members.py:141
|
||||
#: members/views/members.py:140
|
||||
msgid "Successfully added member"
|
||||
msgstr "Successfully added member"
|
||||
|
||||
#: members/views/members.py:162
|
||||
#: members/views/members.py:161
|
||||
msgid "Member missing 'id' field."
|
||||
msgstr "Member missing 'id' field."
|
||||
|
||||
#: members/views/members.py:171
|
||||
#: members/views/members.py:170
|
||||
msgid "Successfully updated member"
|
||||
msgstr "Successfully updated member"
|
||||
|
||||
#: members/views/members.py:192
|
||||
#: members/views/members.py:191
|
||||
msgid "Successfully deleted member"
|
||||
msgstr "Successfully deleted member"
|
||||
|
||||
#: members/views/members.py:201
|
||||
#: members/views/members.py:200
|
||||
msgid "Could not delete member object"
|
||||
msgstr "Could not delete member object"
|
||||
|
||||
#: members/views/payments.py:71
|
||||
#: members/views/payments.py:70
|
||||
msgid "Successfully added payment for member"
|
||||
msgstr "Successfully added payment for member"
|
||||
|
||||
#: members/views/payments.py:88 members/views/payments.py:105
|
||||
#: members/views/payments.py:123
|
||||
#: members/views/payments.py:87 members/views/payments.py:104
|
||||
#: members/views/payments.py:122
|
||||
msgid "No payment id specified"
|
||||
msgstr "No payment id specified"
|
||||
|
||||
#: members/views/payments.py:128
|
||||
#: members/views/payments.py:127
|
||||
msgid "Successfully deleted payment"
|
||||
msgstr "Successfully deleted payment"
|
||||
|
||||
#: members/views/payments.py:136
|
||||
#: members/views/payments.py:135
|
||||
msgid "Could not delete payment object"
|
||||
msgstr "Could not delete payment object"
|
||||
|
||||
#: members/views/payments.py:156
|
||||
#: members/views/payments.py:155
|
||||
msgid "Successfully updated payment"
|
||||
msgstr "Successfully updated payment"
|
||||
|
||||
#: members/views/payments.py:161
|
||||
#: members/views/payments.py:160
|
||||
msgid "Could not update payment object"
|
||||
msgstr "Could not update payment object"
|
||||
|
||||
#: members/views/utils.py:112
|
||||
#: members/views/utils.py:111
|
||||
msgid "Missing CSV file"
|
||||
msgstr "Missing CSV file"
|
||||
|
||||
@@ -932,10 +1058,6 @@ msgstr ""
|
||||
msgid "Ohlhafv challenge: {} vs. {}"
|
||||
msgstr ""
|
||||
|
||||
#: ohlhafv/templates/email.html:2
|
||||
msgid "Moikka"
|
||||
msgstr "Hi"
|
||||
|
||||
#: ohlhafv/templates/email.html:4
|
||||
msgid "on haastanut sinut oluenjuontimittelöön"
|
||||
msgstr "has challenged you to a beer drinking contest"
|
||||
@@ -945,12 +1067,9 @@ msgid "-sarjassa"
|
||||
msgstr "series"
|
||||
|
||||
#: ohlhafv/templates/email.html:8
|
||||
#, fuzzy
|
||||
#| msgid ""
|
||||
#| "Muistattehan vahvistaa haasteen paikan päällä Smökissä torstaina 15.2"
|
||||
msgid "Muistattehan vahvistaa haasteen paikan päällä Smökissä torstaina 14.2"
|
||||
msgstr ""
|
||||
"Remeber to confirm the challenge at Smökki on Thursday 15.2. at the event"
|
||||
"Remeber to confirm the challenge at Smökki on Thursday 14.2. at the event"
|
||||
|
||||
#: ohlhafv/templates/email.html:10
|
||||
msgid "Käy kurkkaamassa muutkin haasteet osoitteessa"
|
||||
@@ -980,7 +1099,7 @@ msgstr ""
|
||||
msgid "Challenge"
|
||||
msgstr "Challenge"
|
||||
|
||||
#: ohlhafv/views.py:43
|
||||
#: ohlhafv/views.py:44
|
||||
msgid "Sinut on haastettu Øhlhäfviin!"
|
||||
msgstr "You have been challenged at Ohlhafv!"
|
||||
|
||||
@@ -993,56 +1112,57 @@ msgstr "Go"
|
||||
msgid "Aalto-yliopiston Sähköinsinöörikilta ry"
|
||||
msgstr "Aalto-yliopiston Sähköinsinöörikilta ry"
|
||||
|
||||
#: webapp/models.py:17
|
||||
#: webapp/models.py:18
|
||||
msgid "Webapp"
|
||||
msgstr "Webapp"
|
||||
|
||||
#: webapp/models.py:28
|
||||
#: webapp/models.py:26
|
||||
msgid "Tag"
|
||||
msgstr "Tag"
|
||||
|
||||
#: webapp/models.py:29
|
||||
#: webapp/models.py:27
|
||||
msgid "Tags"
|
||||
msgstr "Tags"
|
||||
|
||||
#: webapp/models.py:32
|
||||
#: webapp/models.py:34
|
||||
msgid "Tag: {}"
|
||||
msgstr "Tag: {}"
|
||||
|
||||
#: webapp/models.py:53
|
||||
msgid "Feed: {}"
|
||||
msgstr "Feed: {}"
|
||||
|
||||
#: webapp/models.py:56
|
||||
#: webapp/models.py:52
|
||||
msgid "Feed"
|
||||
msgstr ""
|
||||
|
||||
#: webapp/models.py:57
|
||||
#: webapp/models.py:53
|
||||
msgid "Feeds"
|
||||
msgstr ""
|
||||
|
||||
#: webapp/models.py:70
|
||||
msgid "Event: {}"
|
||||
#: webapp/models.py:61 webapp/models.py:80 webapp/models.py:119
|
||||
#: webapp/models.py:152 webapp/models.py:198
|
||||
msgid "Deleted: "
|
||||
msgstr "Deleted: "
|
||||
|
||||
#: webapp/models.py:62
|
||||
msgid "{}Feed: {}"
|
||||
msgstr ""
|
||||
|
||||
#: webapp/models.py:73
|
||||
#: webapp/models.py:69
|
||||
msgid "Event"
|
||||
msgstr ""
|
||||
|
||||
#: webapp/models.py:84
|
||||
msgid "Template questions: {}"
|
||||
#: webapp/models.py:81
|
||||
msgid "{}Event: {}"
|
||||
msgstr ""
|
||||
|
||||
#: webapp/models.py:87
|
||||
#: webapp/models.py:91
|
||||
msgid "Template question"
|
||||
msgstr ""
|
||||
|
||||
#: webapp/models.py:88
|
||||
#: webapp/models.py:92
|
||||
msgid "Template questions"
|
||||
msgstr ""
|
||||
|
||||
#: webapp/models.py:102
|
||||
msgid "#{} {}"
|
||||
#: webapp/models.py:98
|
||||
msgid "Template questions: {}"
|
||||
msgstr ""
|
||||
|
||||
#: webapp/models.py:105
|
||||
@@ -1053,52 +1173,28 @@ msgstr ""
|
||||
msgid "Signup forms"
|
||||
msgstr ""
|
||||
|
||||
#: webapp/models.py:115
|
||||
msgid "Sign-ups: {}"
|
||||
#: webapp/models.py:120
|
||||
msgid "#{} {}{}"
|
||||
msgstr ""
|
||||
|
||||
#: webapp/models.py:118
|
||||
#: webapp/models.py:138
|
||||
msgid "Sign-up"
|
||||
msgstr ""
|
||||
|
||||
#: webapp/models.py:119
|
||||
#: webapp/models.py:139
|
||||
msgid "Sign-ups"
|
||||
msgstr ""
|
||||
|
||||
#: webapp/models.py:130
|
||||
#: webapp/models.py:178
|
||||
msgid "board member"
|
||||
msgstr "board member"
|
||||
|
||||
#: webapp/models.py:148
|
||||
msgid "Committee"
|
||||
msgstr ""
|
||||
|
||||
#: webapp/models.py:149
|
||||
msgid "Committees"
|
||||
msgstr ""
|
||||
|
||||
#: webapp/models.py:152
|
||||
msgid "Committee: {}"
|
||||
msgstr ""
|
||||
|
||||
#: webapp/models.py:172
|
||||
msgid "Role"
|
||||
msgstr ""
|
||||
|
||||
#: webapp/models.py:175
|
||||
msgid "Start date"
|
||||
msgstr ""
|
||||
|
||||
#: webapp/models.py:176
|
||||
msgid "End date"
|
||||
#: webapp/models.py:185
|
||||
msgid "JobAd"
|
||||
msgstr ""
|
||||
|
||||
#: webapp/models.py:186
|
||||
msgid "Official"
|
||||
msgstr ""
|
||||
|
||||
#: webapp/models.py:187
|
||||
msgid "Officials"
|
||||
msgid "JobAds"
|
||||
msgstr ""
|
||||
|
||||
#: webapp/templates/contact.html:9 webapp/templates/navigation.html:20
|
||||
@@ -1144,84 +1240,3 @@ msgstr "Sössö"
|
||||
#: webapp/templates/navigation.html:24
|
||||
msgid "Corporate"
|
||||
msgstr "Corporate"
|
||||
|
||||
#~ msgid "HSL timetables"
|
||||
#~ msgstr "HSL timetables"
|
||||
|
||||
#~ msgid "Username"
|
||||
#~ msgstr "Username"
|
||||
|
||||
#~ msgid "Password"
|
||||
#~ msgstr "Password"
|
||||
|
||||
#~ msgid "Forgot password?"
|
||||
#~ msgstr "Forgot password?"
|
||||
|
||||
#~ msgid "Log in"
|
||||
#~ msgstr "Log in"
|
||||
|
||||
#~ msgid "New password set"
|
||||
#~ msgstr "New password set"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Your password has successfully been reset. You can use it right now on "
|
||||
#~ "the login page."
|
||||
#~ msgstr ""
|
||||
#~ "Your password has successfully been reset. You can use it right now on "
|
||||
#~ "the login page."
|
||||
|
||||
#~ msgid "Password recovery"
|
||||
#~ msgstr "Password recovery"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Sorry, this password reset link is invalid. You can still <a href="
|
||||
#~ "\"%(recovery_url)s\">request a new one</a>."
|
||||
#~ msgstr ""
|
||||
#~ "Sorry, this password reset link is invalid. You can still <a href="
|
||||
#~ "\"%(recovery_url)s\">request a new one</a>."
|
||||
|
||||
#~ msgid "Hi, <strong>%(username)s</strong>. Please choose your new password."
|
||||
#~ msgstr "Hi, <strong>%(username)s</strong>. Please choose your new password."
|
||||
|
||||
#~ msgid "Set new password"
|
||||
#~ msgstr "Set new password"
|
||||
|
||||
#~ msgid "Password recovery sent"
|
||||
#~ msgstr "Password recovery sent"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "An email was sent to <strong>%(email)s</strong> %(ago)s ago. Use the link "
|
||||
#~ "in it to set a new password."
|
||||
#~ msgstr ""
|
||||
#~ "An email was sent to <strong>%(email)s</strong> %(ago)s ago. Use the link "
|
||||
#~ "in it to set a new password."
|
||||
|
||||
#~ msgid "SIK Admin"
|
||||
#~ msgstr "SIK Admin"
|
||||
|
||||
#~ msgid "Admin tools"
|
||||
#~ msgstr "Admin tools"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "\n"
|
||||
#~ " first_name, last_name, email_address and place_of_origin "
|
||||
#~ "should be given string values.\n"
|
||||
#~ " ayy_member and jas_recipient should be given the value 0 "
|
||||
#~ "(off) or 1 (on).\n"
|
||||
#~ " "
|
||||
#~ msgstr ""
|
||||
#~ "\n"
|
||||
#~ " first_name, last_name, email_address and place_of_origin "
|
||||
#~ "should be given string values.\n"
|
||||
#~ " ayy_member and jas_recipient should be given the value 0 "
|
||||
#~ "(off) or 1 (on).\n"
|
||||
#~ " "
|
||||
|
||||
#~ msgid "Syntax"
|
||||
#~ msgstr "Syntax"
|
||||
|
||||
#~ msgid "Missing \"textfield\" POST request field"
|
||||
#~ msgstr "Missing \"textfield\" POST request field"
|
||||
|
||||
#~ msgid "Options"
|
||||
#~ msgstr "Options"
|
||||
|
||||
@@ -7,7 +7,7 @@ msgid ""
|
||||
msgstr ""
|
||||
"Project-Id-Version: \n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"POT-Creation-Date: 2019-03-26 17:32+0200\n"
|
||||
"POT-Creation-Date: 2021-01-18 21:36+0200\n"
|
||||
"PO-Revision-Date: 2017-11-02 23:04+0200\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: \n"
|
||||
@@ -38,7 +38,7 @@ msgstr "Sössön artikkelit"
|
||||
msgid "Today's lunch"
|
||||
msgstr "Päivän lounas"
|
||||
|
||||
#: infoscreen/models.py:212 webapp/models.py:74
|
||||
#: infoscreen/models.py:212 webapp/models.py:70
|
||||
msgid "Events"
|
||||
msgstr "Tapahtumat"
|
||||
|
||||
@@ -113,8 +113,8 @@ msgstr "Esikatsele"
|
||||
msgid "Delete"
|
||||
msgstr "Poista"
|
||||
|
||||
#: infoscreen/templates/tabs/add_remove.html:23 kaehmy/models.py:56
|
||||
#: kaehmy/templates/list.html:36 webapp/models.py:125 webapp/models.py:154
|
||||
#: infoscreen/templates/tabs/add_remove.html:23 kaehmy/models.py:62
|
||||
#: kaehmy/templates/list.html:36 webapp/models.py:144 webapp/models.py:173
|
||||
msgid "Name"
|
||||
msgstr "Nimi"
|
||||
|
||||
@@ -190,7 +190,7 @@ msgstr "Puhelinnumero (ei julkinen)"
|
||||
msgid "Custom roles"
|
||||
msgstr "Uudet virat"
|
||||
|
||||
#: kaehmy/forms.py:49 kaehmy/templates/kaehmy.html:41
|
||||
#: kaehmy/forms.py:49 kaehmy/templates/kaehmy.html:43
|
||||
msgid "Preset roles"
|
||||
msgstr "Kaehmyvirat"
|
||||
|
||||
@@ -202,157 +202,157 @@ msgstr "Virheellinen puhelinnumero"
|
||||
msgid "Custom role with the same name already exists."
|
||||
msgstr "Samanniminen virka on jo olemassa."
|
||||
|
||||
#: kaehmy/models.py:13
|
||||
#: kaehmy/models.py:18
|
||||
msgid "Kaehmy"
|
||||
msgstr "Kaehmy"
|
||||
|
||||
#: kaehmy/models.py:19
|
||||
#: kaehmy/models.py:25
|
||||
msgid "Corporate affairs"
|
||||
msgstr "Yrityssuhteet"
|
||||
|
||||
#: kaehmy/models.py:20 webapp/templates/freshmen.html:10
|
||||
#: kaehmy/models.py:26 webapp/templates/freshmen.html:10
|
||||
#: webapp/templates/navigation.html:8
|
||||
msgid "Freshmen"
|
||||
msgstr "Fuksit"
|
||||
|
||||
#: kaehmy/models.py:21 webapp/templates/international.html:10
|
||||
#: kaehmy/models.py:27 webapp/templates/international.html:10
|
||||
#: webapp/templates/navigation.html:14
|
||||
msgid "International"
|
||||
msgstr "International"
|
||||
|
||||
#: kaehmy/models.py:22
|
||||
#: kaehmy/models.py:28
|
||||
msgid "External affairs"
|
||||
msgstr "Ulkosuhteet"
|
||||
|
||||
#: kaehmy/models.py:23
|
||||
#: kaehmy/models.py:29
|
||||
msgid "Media"
|
||||
msgstr "Media"
|
||||
|
||||
#: kaehmy/models.py:24
|
||||
#: kaehmy/models.py:30
|
||||
msgid "Technology"
|
||||
msgstr "Teknologia"
|
||||
|
||||
#: kaehmy/models.py:25
|
||||
#: kaehmy/models.py:31
|
||||
msgid "Wellbeing"
|
||||
msgstr "Hyvinvointi"
|
||||
|
||||
#: kaehmy/models.py:26
|
||||
#: kaehmy/models.py:32
|
||||
msgid "Elepaja"
|
||||
msgstr "Elepaja"
|
||||
|
||||
#: kaehmy/models.py:27
|
||||
#: kaehmy/models.py:33
|
||||
msgid "Ceremonies"
|
||||
msgstr "Hupitapahtumat"
|
||||
|
||||
#: kaehmy/models.py:28
|
||||
#: kaehmy/models.py:34
|
||||
msgid "Studies"
|
||||
msgstr "Opinnot"
|
||||
|
||||
#: kaehmy/models.py:29
|
||||
#: kaehmy/models.py:35
|
||||
msgid "Sössö magazine"
|
||||
msgstr "Kiltalehti Sössö"
|
||||
|
||||
#: kaehmy/models.py:30
|
||||
#: kaehmy/models.py:36
|
||||
msgid "Alumni relations"
|
||||
msgstr "Alumnisuhteet"
|
||||
|
||||
#: kaehmy/models.py:31
|
||||
#: kaehmy/models.py:37
|
||||
msgid "Others"
|
||||
msgstr "Muut"
|
||||
|
||||
#: kaehmy/models.py:33
|
||||
#: kaehmy/models.py:39
|
||||
msgid "Category"
|
||||
msgstr "Kategoria"
|
||||
|
||||
#: kaehmy/models.py:39 webapp/models.py:136
|
||||
#: kaehmy/models.py:45
|
||||
msgid "Description"
|
||||
msgstr "Kuvaus"
|
||||
|
||||
#: kaehmy/models.py:42
|
||||
#: kaehmy/models.py:48
|
||||
msgid "Preset kaehmy role"
|
||||
msgstr "Kaehmyvirka"
|
||||
|
||||
#: kaehmy/models.py:43
|
||||
#: kaehmy/models.py:49
|
||||
msgid "Preset kaehmy roles"
|
||||
msgstr "Kaehmyvirat"
|
||||
|
||||
#: kaehmy/models.py:50
|
||||
#: kaehmy/models.py:56
|
||||
msgid "Custom kaehmy role"
|
||||
msgstr "Uusi virka"
|
||||
|
||||
#: kaehmy/models.py:51
|
||||
#: kaehmy/models.py:57
|
||||
msgid "Custom kaehmy roles"
|
||||
msgstr "Uudet kaehmyvirat"
|
||||
|
||||
#: kaehmy/models.py:57 kaehmy/templates/list.html:40 members/models.py:15
|
||||
#: kaehmy/models.py:63 kaehmy/templates/list.html:40 members/models.py:14
|
||||
msgid "Email"
|
||||
msgstr "Sähköposti"
|
||||
|
||||
#: kaehmy/models.py:58
|
||||
#: kaehmy/models.py:64
|
||||
msgid "Timestamp"
|
||||
msgstr "Aikaleima"
|
||||
|
||||
#: kaehmy/models.py:72
|
||||
#: kaehmy/models.py:78
|
||||
msgid "Kaehmykommentti"
|
||||
msgstr "Kaehmykommentti"
|
||||
|
||||
#: kaehmy/models.py:73
|
||||
#: kaehmy/models.py:79
|
||||
msgid "Kaehmykommentit"
|
||||
msgstr "Kaehmykommentit"
|
||||
|
||||
#: kaehmy/models.py:75 ohlhafv/models.py:36
|
||||
#: kaehmy/models.py:81 ohlhafv/models.py:36
|
||||
msgid "Message"
|
||||
msgstr "Viesti"
|
||||
|
||||
#: kaehmy/models.py:94 kaehmy/templates/kaehmy.html:12
|
||||
#: kaehmy/models.py:100 kaehmy/templates/kaehmy.html:12
|
||||
msgid "Kaehmylomake"
|
||||
msgstr "Kaehmylomake"
|
||||
|
||||
#: kaehmy/models.py:95
|
||||
#: kaehmy/models.py:101
|
||||
msgid "Kaehmylomakkeet"
|
||||
msgstr "Kaehmylomakkeet"
|
||||
|
||||
#: kaehmy/models.py:98 webapp/models.py:189
|
||||
#: kaehmy/models.py:104
|
||||
msgid "Phone number"
|
||||
msgstr "Puhelinnumero"
|
||||
|
||||
#: kaehmy/models.py:99
|
||||
#: kaehmy/models.py:105
|
||||
msgid "Year"
|
||||
msgstr "Vuosi"
|
||||
|
||||
#: kaehmy/models.py:100
|
||||
#: kaehmy/models.py:106
|
||||
msgid "Text"
|
||||
msgstr "Teksti"
|
||||
|
||||
#: kaehmy/models.py:102
|
||||
#: kaehmy/models.py:108
|
||||
msgid "Custom role name"
|
||||
msgstr "Uusi virka"
|
||||
|
||||
#: kaehmy/models.py:104 webapp/models.py:126
|
||||
#: kaehmy/models.py:110 webapp/models.py:174
|
||||
msgid "Board member"
|
||||
msgstr "Hallituksen jäsen"
|
||||
|
||||
#: kaehmy/models.py:112
|
||||
#: kaehmy/models.py:118
|
||||
msgid "Kaehmy application: {}"
|
||||
msgstr "Kaehmy: {}"
|
||||
|
||||
#: kaehmy/models.py:134
|
||||
#: kaehmy/models.py:140
|
||||
msgid "Board: {}"
|
||||
msgstr "Hallitus: {}"
|
||||
|
||||
#: kaehmy/models.py:140
|
||||
#: kaehmy/models.py:146
|
||||
msgid "Official: {}"
|
||||
msgstr "Toimari: {}"
|
||||
|
||||
#: kaehmy/models.py:157
|
||||
#: kaehmy/models.py:163
|
||||
msgid "Telegram channel"
|
||||
msgstr "Telegram-kanava"
|
||||
|
||||
#: kaehmy/models.py:158
|
||||
#: kaehmy/models.py:164
|
||||
msgid "Telegram channels"
|
||||
msgstr "Telegram-kanavat"
|
||||
|
||||
#: kaehmy/tables.py:13 webapp/models.py:173
|
||||
#: kaehmy/tables.py:13
|
||||
msgid "Roles"
|
||||
msgstr "Roolit"
|
||||
|
||||
@@ -393,7 +393,8 @@ msgid ""
|
||||
" Koska lista ei ole koskaan täydellinen, voit myös ehdottaa ihan "
|
||||
"uutta toimenkuvaa.\n"
|
||||
" Jos sinulla on kysyttävää mistä tahansa virasta, kannattaa "
|
||||
"konsultoida <a href=\"/static/other/kahmyopas.pdf\">kaehmyopasta</a> \n"
|
||||
"konsultoida <a href=\"https://static.sahkoinsinoorikilta.fi/uus_webi/"
|
||||
"kahmyopas.pdf\">kaehmyopasta</a>\n"
|
||||
" tai olla yhteydessä kyseistä virkaa tänä vuonna toimittavaan "
|
||||
"henkilöön."
|
||||
msgstr ""
|
||||
@@ -403,13 +404,20 @@ msgstr ""
|
||||
" Koska lista ei ole koskaan täydellinen, voit myös ehdottaa ihan "
|
||||
"uutta toimenkuvaa.\n"
|
||||
" Jos sinulla on kysyttävää mistä tahansa virasta, kannattaa "
|
||||
"konsultoida <a href=\"/static/other/kahmyopas.pdf\">kaehmyopasta</a> \n"
|
||||
"konsultoida <a href=\"https://static.sahkoinsinoorikilta.fi/uus_webi/kahmyopas.pdf"
|
||||
"\">kaehmyopasta</a> \n"
|
||||
" tai olla yhteydessä kyseistä virkaa tänä vuonna toimittavaan "
|
||||
"henkilöön."
|
||||
|
||||
#: kaehmy/templates/kaehmy.html:23
|
||||
msgid ""
|
||||
"Muista, että kaehmyn lähettäminen on kiinnostuksen ilmaus \n"
|
||||
"(HUOM! Kaehmytekstin maksimipituus on 300 merkkiä. Tarvittaessa voit "
|
||||
"kirjoittaa lisätietoja kommenteihin.)"
|
||||
msgstr ""
|
||||
|
||||
#: kaehmy/templates/kaehmy.html:26
|
||||
msgid ""
|
||||
"Muista, että kaehmyn lähettäminen on kiinnostuksen ilmaus\n"
|
||||
" eikä siis missään nimessä sitova ilmoittautumien mihinkään "
|
||||
"tehtävään!"
|
||||
msgstr ""
|
||||
@@ -417,35 +425,31 @@ msgstr ""
|
||||
" eikä siis missään nimessä sitova ilmoittautumien mihinkään "
|
||||
"tehtävään!"
|
||||
|
||||
#: kaehmy/templates/kaehmy.html:26
|
||||
#: kaehmy/templates/kaehmy.html:29
|
||||
msgid "Päivämääriä & deadlineja"
|
||||
msgstr "Päivämääriä & deadlineja"
|
||||
|
||||
#: kaehmy/templates/kaehmy.html:28
|
||||
msgid "Hallitustyrkkypaneeli (haku hallitukseen olisi hyvä tehdä ennen tätä!)"
|
||||
msgstr "Hallitustyrkkypaneeli (haku hallitukseen olisi hyvä tehdä ennen tätä!)"
|
||||
#: kaehmy/templates/kaehmy.html:31
|
||||
msgid "Hallitustyrkkypaneeli"
|
||||
msgstr ""
|
||||
|
||||
#: kaehmy/templates/kaehmy.html:29
|
||||
#: kaehmy/templates/kaehmy.html:32
|
||||
msgid "Vaalikokous, osa 1 (puheenjohtajan valinta)"
|
||||
msgstr "Vaalikokous, osa 1 (puheenjohtajan valinta)"
|
||||
|
||||
#: kaehmy/templates/kaehmy.html:30
|
||||
msgid "Kiltailta"
|
||||
msgstr "Kiltailta"
|
||||
#: kaehmy/templates/kaehmy.html:33
|
||||
msgid "Toimikunta-appro"
|
||||
msgstr ""
|
||||
|
||||
#: kaehmy/templates/kaehmy.html:31
|
||||
#: kaehmy/templates/kaehmy.html:34
|
||||
msgid "Vaalikokous, osa 2 (hallituksen valinta)"
|
||||
msgstr "Vaalikokous, osa 2 (hallituksen valinta)"
|
||||
|
||||
#: kaehmy/templates/kaehmy.html:32
|
||||
msgid "Haku toimariksi olisi hyvä tehdä ennen tätä!"
|
||||
msgstr "Haku toimariksi olisi hyvä tehdä ennen tätä!"
|
||||
|
||||
#: kaehmy/templates/kaehmy.html:33
|
||||
#: kaehmy/templates/kaehmy.html:35
|
||||
msgid "Vaalikokous, osa 3 (toimarien valinta)"
|
||||
msgstr "Vaalikokous, osa 3 (toimarien valinta)"
|
||||
|
||||
#: kaehmy/templates/kaehmy.html:76
|
||||
#: kaehmy/templates/kaehmy.html:78
|
||||
#, python-format
|
||||
msgid ""
|
||||
"\n"
|
||||
@@ -456,7 +460,7 @@ msgid ""
|
||||
" "
|
||||
msgstr ""
|
||||
|
||||
#: kaehmy/templates/kaehmy.html:82 members/templates/settings.html:23
|
||||
#: kaehmy/templates/kaehmy.html:84 members/templates/settings.html:23
|
||||
msgid "Submit"
|
||||
msgstr "Lisää"
|
||||
|
||||
@@ -510,7 +514,7 @@ msgstr "Uusi kaehmy"
|
||||
msgid "Statistics"
|
||||
msgstr "Kaehmytilastot"
|
||||
|
||||
#: members/forms.py:107 members/models.py:102 members/tables.py:41
|
||||
#: members/forms.py:107 members/models.py:101 members/tables.py:41
|
||||
msgid "Member"
|
||||
msgstr "Jäsen"
|
||||
|
||||
@@ -522,52 +526,52 @@ msgstr "Olen AYY:n jäsen"
|
||||
msgid "I want to receive a weekly newsletter"
|
||||
msgstr "Haluan saada viikottaisen jäsentiedotteen"
|
||||
|
||||
#: members/models.py:13
|
||||
#: members/models.py:12
|
||||
msgid "First name"
|
||||
msgstr "Etunimi"
|
||||
|
||||
#: members/models.py:14
|
||||
#: members/models.py:13
|
||||
msgid "Last name"
|
||||
msgstr "Sukunimi"
|
||||
|
||||
#: members/models.py:16
|
||||
#: members/models.py:15
|
||||
msgid "Place of residence"
|
||||
msgstr "Asuinpaikka"
|
||||
|
||||
#: members/models.py:18 members/models.py:69
|
||||
#: members/models.py:17 members/models.py:68
|
||||
#: members/templates/member_add_many.html:39
|
||||
msgid "AYY"
|
||||
msgstr "AYY"
|
||||
|
||||
#: members/models.py:19
|
||||
#: members/models.py:18
|
||||
msgid "JAS"
|
||||
msgstr "JAS"
|
||||
|
||||
#: members/models.py:50
|
||||
#: members/models.py:49
|
||||
msgid "Submitted"
|
||||
msgstr "Lisätty"
|
||||
|
||||
#: members/models.py:67
|
||||
#: members/models.py:66
|
||||
msgid "Date"
|
||||
msgstr "Päivämäärä"
|
||||
|
||||
#: members/models.py:68
|
||||
#: members/models.py:67
|
||||
msgid "Source"
|
||||
msgstr "Lähde"
|
||||
|
||||
#: members/models.py:70
|
||||
#: members/models.py:69
|
||||
msgid "Cash"
|
||||
msgstr "Käteinen"
|
||||
|
||||
#: members/models.py:71 members/templates/member_add_many.html:40
|
||||
#: members/models.py:70 members/templates/member_add_many.html:40
|
||||
msgid "Bank transfer"
|
||||
msgstr "Tilisiirto"
|
||||
|
||||
#: members/models.py:95
|
||||
#: members/models.py:94
|
||||
msgid "Created"
|
||||
msgstr "Lisätty"
|
||||
|
||||
#: members/models.py:103 members/templates/base.html:53
|
||||
#: members/models.py:102 members/templates/base.html:53
|
||||
#: members/templates/member_add_many_confirm.html:12
|
||||
msgid "Members"
|
||||
msgstr "Jäsenet"
|
||||
@@ -632,6 +636,12 @@ msgid "Hienoa! Jäsenhakemuksesi on nyt lähetetty."
|
||||
msgstr "Hienoa! Jäsenhakemuksesi on nyt lähetetty."
|
||||
|
||||
#: members/templates/application_success.html:9
|
||||
msgid ""
|
||||
"Vahvistusviesti on lähetetty sähköpostiisi. Ota yhteyttä sik-vtmk@list.ayy."
|
||||
"fi jos viestiä ei näy."
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/application_success.html:10
|
||||
msgid "Takaisin Sähköinsinöörikillan web-sivuille"
|
||||
msgstr "Takaisin Sähköinsinöörikillan web-sivuille"
|
||||
|
||||
@@ -685,6 +695,101 @@ msgstr "Jäsenhakemuslomake"
|
||||
msgid "Settings"
|
||||
msgstr "Asetukset"
|
||||
|
||||
#: members/templates/email_application_accept.html:2
|
||||
msgid "Moi"
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/email_application_accept.html:4
|
||||
msgid "Onnittelut! Sinut on hyväksytty Sähköinsinöörikillan jäseneksi."
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/email_application_accept.html:6
|
||||
msgid "Käy kurkkaamassa killan nettisivuilta"
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/email_application_accept.html:6
|
||||
msgid ""
|
||||
"tulevia tapahtumia ja piipahda kiltahuoneella tutustumassa uusiin "
|
||||
"kiltatovereihisi!"
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/email_application_accept.html:8
|
||||
msgid "Liity myös killan TG-kanaville"
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/email_application_accept.html:9
|
||||
msgid "SIK"
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/email_application_accept.html:10
|
||||
msgid "SIK-fuksit 2019"
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/email_application_accept.html:11
|
||||
msgid "SIK-fuksit 2019 -tiedotuskanava"
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/email_application_submit.html:2
|
||||
#: ohlhafv/templates/email.html:2
|
||||
msgid "Moikka"
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/email_application_submit.html:4
|
||||
msgid ""
|
||||
"Sait tämän viestin, sillä olet lähettänyt hakemuksen Aalto-yliopiston "
|
||||
"Sähköinsinöörikillan jäseneksi alla olevin tiedoin. Siistiä!"
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/email_application_submit.html:6
|
||||
msgid "Etunimi"
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/email_application_submit.html:7
|
||||
msgid "Sukunimi"
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/email_application_submit.html:8
|
||||
msgid "Sähköposti"
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/email_application_submit.html:9
|
||||
msgid "Kotipaikkakunta"
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/email_application_submit.html:10
|
||||
msgid "AYY:n jäsen"
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/email_application_submit.html:11
|
||||
msgid "Haluan jäsenmailin"
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/email_application_submit.html:13
|
||||
msgid ""
|
||||
"Saat sähköpostiisi tiedon, kun sinut on hallituksen kokouksessa hyväksytty "
|
||||
"jäseneksi"
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/email_application_submit.html:15
|
||||
msgid "Muistathan maksaa jäsenmaksun! Alla maksutiedot"
|
||||
msgstr "Muistathan maksaa jäsenmaksun! Alla maksutiedot"
|
||||
|
||||
#: members/templates/email_application_submit.html:17
|
||||
msgid "Saaja"
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/email_application_submit.html:18
|
||||
msgid "Tilinumero"
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/email_application_submit.html:20
|
||||
msgid "Viite"
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/email_application_submit.html:21
|
||||
msgid "Summa"
|
||||
msgstr ""
|
||||
|
||||
#: members/templates/member_add.html:15 members/templates/member_edit.html:18
|
||||
#: members/templates/payment_add.html:20 members/templates/payment_edit.html:18
|
||||
msgid "Save"
|
||||
@@ -800,94 +905,110 @@ msgstr "Maksutapahtumia:"
|
||||
msgid "Language"
|
||||
msgstr "Kieli"
|
||||
|
||||
#: members/templates/settings.html:20 sikweb/base.py:255
|
||||
#: members/templates/settings.html:20 sikweb/base.py:217
|
||||
msgid "Finnish"
|
||||
msgstr "suomi"
|
||||
|
||||
#: members/templates/settings.html:21 sikweb/base.py:256
|
||||
#: members/templates/settings.html:21 sikweb/base.py:218
|
||||
msgid "English"
|
||||
msgstr "englanti"
|
||||
|
||||
#: members/views/applications.py:51 members/views/applications.py:112
|
||||
#: members/views/applications.py:137
|
||||
#: members/views/applications.py:53 members/views/applications.py:124
|
||||
#: members/views/applications.py:149
|
||||
msgid "No application id specified"
|
||||
msgstr "Hakemuksen ID ei määritelty"
|
||||
|
||||
#: members/views/applications.py:71
|
||||
#: members/views/applications.py:73
|
||||
msgid "Application missing 'id' field."
|
||||
msgstr "Hakemuksen ID ei määritelty."
|
||||
|
||||
#: members/views/applications.py:80
|
||||
#: members/views/applications.py:82
|
||||
msgid "Email {} is already in use by a member. Application cannot be accepted."
|
||||
msgstr "Sähköpostiosoite {} on jo käytössä. Hakemusta ei hyväksytty."
|
||||
|
||||
#: members/views/applications.py:91
|
||||
#: members/views/applications.py:93
|
||||
msgid "Successfully accepted application"
|
||||
msgstr "Onnistuneesti hyväksyttiin hakemus"
|
||||
|
||||
#: members/views/applications.py:116
|
||||
#: members/views/applications.py:96
|
||||
msgid "Jäsenhakemuksesi Sähköinsinöörikiltaan on hyväksytty!"
|
||||
msgstr ""
|
||||
|
||||
#: members/views/applications.py:128
|
||||
msgid "Successfully deleted application"
|
||||
msgstr "Onnistuneesti poistettiin hakemus"
|
||||
|
||||
#: members/views/applications.py:126
|
||||
#: members/views/applications.py:138
|
||||
msgid "Could not delete application object"
|
||||
msgstr "Hakemusobjektia ei voitu poistaa"
|
||||
|
||||
#: members/views/members.py:86 members/views/members.py:188
|
||||
#: members/views/members.py:212
|
||||
#: members/views/applications.py:176
|
||||
msgid "Jäsenhakemuksesi Sähköinsinöörikiltaan on lähetetty onnistuneesti!"
|
||||
msgstr ""
|
||||
|
||||
#: members/views/applications.py:181 members/views/applications.py:182
|
||||
msgid "Kyllä"
|
||||
msgstr ""
|
||||
|
||||
#: members/views/applications.py:181 members/views/applications.py:182
|
||||
msgid "Ei"
|
||||
msgstr ""
|
||||
|
||||
#: members/views/members.py:85 members/views/members.py:187
|
||||
#: members/views/members.py:211
|
||||
msgid "No member id specified"
|
||||
msgstr "Jäsenen ID ei määritelty"
|
||||
|
||||
#: members/views/members.py:127
|
||||
#: members/views/members.py:126
|
||||
msgid "Failed to import members"
|
||||
msgstr "Jäsenten tuonti epäonnistui"
|
||||
|
||||
#: members/views/members.py:141
|
||||
#: members/views/members.py:140
|
||||
msgid "Successfully added member"
|
||||
msgstr "Onnistuneesti lisättiin jäsen"
|
||||
|
||||
#: members/views/members.py:162
|
||||
#: members/views/members.py:161
|
||||
msgid "Member missing 'id' field."
|
||||
msgstr "Jäsenen ID ei määritelty."
|
||||
|
||||
#: members/views/members.py:171
|
||||
#: members/views/members.py:170
|
||||
msgid "Successfully updated member"
|
||||
msgstr "Onnistuneesti päivitettiin jäsen"
|
||||
|
||||
#: members/views/members.py:192
|
||||
#: members/views/members.py:191
|
||||
msgid "Successfully deleted member"
|
||||
msgstr "Onnistuneesti poistettiin jäsen"
|
||||
|
||||
#: members/views/members.py:201
|
||||
#: members/views/members.py:200
|
||||
msgid "Could not delete member object"
|
||||
msgstr "Jäsenobjektia ei voitu poistaa"
|
||||
|
||||
#: members/views/payments.py:71
|
||||
#: members/views/payments.py:70
|
||||
msgid "Successfully added payment for member"
|
||||
msgstr "Onnistuneesti lisättiin maksutapahtuma jäsenelle"
|
||||
|
||||
#: members/views/payments.py:88 members/views/payments.py:105
|
||||
#: members/views/payments.py:123
|
||||
#: members/views/payments.py:87 members/views/payments.py:104
|
||||
#: members/views/payments.py:122
|
||||
msgid "No payment id specified"
|
||||
msgstr "Maksutapahtuman ID ei määritelty"
|
||||
|
||||
#: members/views/payments.py:128
|
||||
#: members/views/payments.py:127
|
||||
msgid "Successfully deleted payment"
|
||||
msgstr "Onnistuneesti poistettiin maksutapahtuma"
|
||||
|
||||
#: members/views/payments.py:136
|
||||
#: members/views/payments.py:135
|
||||
msgid "Could not delete payment object"
|
||||
msgstr "Maksutapahtumaobjektia ei voitu poistaa"
|
||||
|
||||
#: members/views/payments.py:156
|
||||
#: members/views/payments.py:155
|
||||
msgid "Successfully updated payment"
|
||||
msgstr "Onnistuneesti päivitettiin maksutapahtuma"
|
||||
|
||||
#: members/views/payments.py:161
|
||||
#: members/views/payments.py:160
|
||||
msgid "Could not update payment object"
|
||||
msgstr "Maksutapahtumaobjektia ei voitu päivittää"
|
||||
|
||||
#: members/views/utils.py:112
|
||||
#: members/views/utils.py:111
|
||||
msgid "Missing CSV file"
|
||||
msgstr "Puuttuva CSV-tiedosto"
|
||||
|
||||
@@ -927,10 +1048,6 @@ msgstr "Sarja"
|
||||
msgid "Ohlhafv challenge: {} vs. {}"
|
||||
msgstr "Ohlhafv-haaste: {} vs. {}"
|
||||
|
||||
#: ohlhafv/templates/email.html:2
|
||||
msgid "Moikka"
|
||||
msgstr ""
|
||||
|
||||
#: ohlhafv/templates/email.html:4
|
||||
msgid "on haastanut sinut oluenjuontimittelöön"
|
||||
msgstr ""
|
||||
@@ -971,7 +1088,7 @@ msgstr "Haasta kaverisi mittelöön!"
|
||||
msgid "Challenge"
|
||||
msgstr "Haasta"
|
||||
|
||||
#: ohlhafv/views.py:43
|
||||
#: ohlhafv/views.py:44
|
||||
msgid "Sinut on haastettu Øhlhäfviin!"
|
||||
msgstr ""
|
||||
|
||||
@@ -984,57 +1101,58 @@ msgstr "Vaihda"
|
||||
msgid "Aalto-yliopiston Sähköinsinöörikilta ry"
|
||||
msgstr "Aalto-yliopiston Sähköinsinöörikilta ry"
|
||||
|
||||
#: webapp/models.py:17
|
||||
#: webapp/models.py:18
|
||||
msgid "Webapp"
|
||||
msgstr "Nettisivut"
|
||||
|
||||
#: webapp/models.py:28
|
||||
#: webapp/models.py:26
|
||||
msgid "Tag"
|
||||
msgstr "Tunniste"
|
||||
|
||||
#: webapp/models.py:29
|
||||
#: webapp/models.py:27
|
||||
msgid "Tags"
|
||||
msgstr "Tunnisteet"
|
||||
|
||||
#: webapp/models.py:32
|
||||
#: webapp/models.py:34
|
||||
msgid "Tag: {}"
|
||||
msgstr "Tunniste: {}"
|
||||
|
||||
#: webapp/models.py:53
|
||||
msgid "Feed: {}"
|
||||
msgstr "Uutinen: {}"
|
||||
|
||||
#: webapp/models.py:56
|
||||
#: webapp/models.py:52
|
||||
msgid "Feed"
|
||||
msgstr "Uutinen"
|
||||
|
||||
#: webapp/models.py:57
|
||||
#: webapp/models.py:53
|
||||
msgid "Feeds"
|
||||
msgstr "Uutiset"
|
||||
|
||||
#: webapp/models.py:70
|
||||
msgid "Event: {}"
|
||||
msgstr "Tapahtuma: {}"
|
||||
#: webapp/models.py:61 webapp/models.py:80 webapp/models.py:119
|
||||
#: webapp/models.py:152 webapp/models.py:198
|
||||
msgid "Deleted: "
|
||||
msgstr "Poistettu: "
|
||||
|
||||
#: webapp/models.py:73
|
||||
#: webapp/models.py:62
|
||||
msgid "{}Feed: {}"
|
||||
msgstr "{}Uutinen: {}"
|
||||
|
||||
#: webapp/models.py:69
|
||||
msgid "Event"
|
||||
msgstr "Tapahtuma"
|
||||
|
||||
#: webapp/models.py:84
|
||||
msgid "Template questions: {}"
|
||||
msgstr "Vakiokysymykset: {}"
|
||||
#: webapp/models.py:81
|
||||
msgid "{}Event: {}"
|
||||
msgstr "{}Tapahtuma: {}"
|
||||
|
||||
#: webapp/models.py:87
|
||||
#: webapp/models.py:91
|
||||
msgid "Template question"
|
||||
msgstr "Vakiokysymys"
|
||||
|
||||
#: webapp/models.py:88
|
||||
#: webapp/models.py:92
|
||||
msgid "Template questions"
|
||||
msgstr "Vakiokysymykset"
|
||||
|
||||
#: webapp/models.py:102
|
||||
msgid "#{} {}"
|
||||
msgstr ""
|
||||
#: webapp/models.py:98
|
||||
msgid "Template questions: {}"
|
||||
msgstr "Vakiokysymykset: {}"
|
||||
|
||||
#: webapp/models.py:105
|
||||
msgid "Signup form"
|
||||
@@ -1044,53 +1162,29 @@ msgstr "Ilmoittautumislomake"
|
||||
msgid "Signup forms"
|
||||
msgstr "Ilmoittautumislomakkeet"
|
||||
|
||||
#: webapp/models.py:115
|
||||
msgid "Sign-ups: {}"
|
||||
msgstr "Ilmoittautumiset: {}"
|
||||
#: webapp/models.py:120
|
||||
msgid "#{} {}{}"
|
||||
msgstr ""
|
||||
|
||||
#: webapp/models.py:118
|
||||
#: webapp/models.py:138
|
||||
msgid "Sign-up"
|
||||
msgstr "Ilmoittautuminen"
|
||||
|
||||
#: webapp/models.py:119
|
||||
#: webapp/models.py:139
|
||||
msgid "Sign-ups"
|
||||
msgstr "Ilmoittautumiset"
|
||||
|
||||
#: webapp/models.py:130
|
||||
#: webapp/models.py:178
|
||||
msgid "board member"
|
||||
msgstr "hallituksen jäsen"
|
||||
|
||||
#: webapp/models.py:148
|
||||
msgid "Committee"
|
||||
msgstr "Toimikunta"
|
||||
|
||||
#: webapp/models.py:149
|
||||
msgid "Committees"
|
||||
msgstr "Toimikunnat"
|
||||
|
||||
#: webapp/models.py:152
|
||||
msgid "Committee: {}"
|
||||
msgstr "Toimikunta: {}"
|
||||
|
||||
#: webapp/models.py:172
|
||||
msgid "Role"
|
||||
msgstr "Rooli"
|
||||
|
||||
#: webapp/models.py:175
|
||||
msgid "Start date"
|
||||
msgstr "Alkupäivämäärä"
|
||||
|
||||
#: webapp/models.py:176
|
||||
msgid "End date"
|
||||
msgstr "Loppupäivämäärä"
|
||||
#: webapp/models.py:185
|
||||
msgid "JobAd"
|
||||
msgstr "Työpaikkailmoitus"
|
||||
|
||||
#: webapp/models.py:186
|
||||
msgid "Official"
|
||||
msgstr "Toimihenkilö"
|
||||
|
||||
#: webapp/models.py:187
|
||||
msgid "Officials"
|
||||
msgstr "Toimihenkilöt"
|
||||
msgid "JobAds"
|
||||
msgstr "Työpaikkailmoitukset"
|
||||
|
||||
#: webapp/templates/contact.html:9 webapp/templates/navigation.html:20
|
||||
msgid "Contact"
|
||||
@@ -1135,104 +1229,3 @@ msgstr "Sössö"
|
||||
#: webapp/templates/navigation.html:24
|
||||
msgid "Corporate"
|
||||
msgstr "Yritys"
|
||||
|
||||
#~ msgid "HSL timetables"
|
||||
#~ msgstr "HSL-aikataulut"
|
||||
|
||||
#~ msgid "Culture"
|
||||
#~ msgstr "Kulttuuri"
|
||||
|
||||
#~ msgid "Username"
|
||||
#~ msgstr "Käyttäjänimi"
|
||||
|
||||
#~ msgid "Password"
|
||||
#~ msgstr "Salasana"
|
||||
|
||||
#~ msgid "Forgot password?"
|
||||
#~ msgstr "Unohditko salasanasi?"
|
||||
|
||||
#~ msgid "Log in"
|
||||
#~ msgstr "Kirjaudu sisään"
|
||||
|
||||
#~ msgid "New password set"
|
||||
#~ msgstr "Uusi salasana asetettu"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Your password has successfully been reset. You can use it right now on "
|
||||
#~ "the login page."
|
||||
#~ msgstr ""
|
||||
#~ "Salasanasi on asetettu onnistuneesti. Voit käyttää sitä nyt "
|
||||
#~ "kirjautuessasi."
|
||||
|
||||
#~ msgid "Password recovery"
|
||||
#~ msgstr "Salasanan palautus"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "Sorry, this password reset link is invalid. You can still <a href="
|
||||
#~ "\"%(recovery_url)s\">request a new one</a>."
|
||||
#~ msgstr ""
|
||||
#~ "Pahoittelut, tämä salasanan palautuslinkki on epäkelpo. Voit kuitenkin <a "
|
||||
#~ "href=\"%(recovery_url)s\">hankkia uuden</a>."
|
||||
|
||||
#~ msgid "Hi, <strong>%(username)s</strong>. Please choose your new password."
|
||||
#~ msgstr "Hei, <strong>%(username)s</strong>. Valitse uusi salasanasi."
|
||||
|
||||
#~ msgid "Set new password"
|
||||
#~ msgstr "Aseta uusi salasana"
|
||||
|
||||
#~ msgid "Password recovery sent"
|
||||
#~ msgstr "Salasanan palautusviesti lähetetty"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "An email was sent to <strong>%(email)s</strong> %(ago)s ago. Use the link "
|
||||
#~ "in it to set a new password."
|
||||
#~ msgstr ""
|
||||
#~ "Sähköposti on lähetetty osoitteeseen <strong>%(email)s</strong> %(ago)s:a "
|
||||
#~ "sitten. Käytä linkkiä asettaaksesi uuden salasanan."
|
||||
|
||||
#~ msgid "Registration: {}"
|
||||
#~ msgstr "Registration: {}"
|
||||
|
||||
#~ msgid "Registration"
|
||||
#~ msgstr "Ilmoittautuminen"
|
||||
|
||||
#~ msgid "Registrations"
|
||||
#~ msgstr "Ilmoittautumiset"
|
||||
|
||||
#~ msgid "Challenger email"
|
||||
#~ msgstr "Haastajan sähköpostiosoite"
|
||||
|
||||
#~ msgid "SIK Admin"
|
||||
#~ msgstr "SIK Hallintapaneeli"
|
||||
|
||||
#~ msgid "Team"
|
||||
#~ msgstr "Joukkue"
|
||||
|
||||
#~ msgid "Admin tools"
|
||||
#~ msgstr "Hallintatyökalut"
|
||||
|
||||
#~ msgid ""
|
||||
#~ "\n"
|
||||
#~ " first_name, last_name, email_address and place_of_origin "
|
||||
#~ "should be given string values.\n"
|
||||
#~ " ayy_member and jas_recipient should be given the value 0 "
|
||||
#~ "(off) or 1 (on).\n"
|
||||
#~ " "
|
||||
#~ msgstr ""
|
||||
#~ "\n"
|
||||
#~ " first_name, last_name, email_address ja place_of_origin ovat "
|
||||
#~ "merkkijonoja.\n"
|
||||
#~ " ayy_member ja jas_recipient ovat joko 0 (off) tai 1 (on).\n"
|
||||
#~ " "
|
||||
|
||||
#~ msgid "Syntax"
|
||||
#~ msgstr "Syntaksi"
|
||||
|
||||
#~ msgid "Data"
|
||||
#~ msgstr "Data"
|
||||
|
||||
#~ msgid "Missing \"textfield\" POST request field"
|
||||
#~ msgstr "Puuttuva \"textfield\" POST-kenttä"
|
||||
|
||||
#~ msgid "Applied for board"
|
||||
#~ msgstr "Hakenut hallitukseen"
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
from django.core.management.base import BaseCommand, CommandError
|
||||
from django.contrib.auth.models import User, Permission
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
||||
|
||||
class Command(BaseCommand):
|
||||
user_name = "sahkopiikki"
|
||||
password = User.objects.make_random_password()
|
||||
|
||||
def handle(self, *args, **options):
|
||||
if User.objects.filter(username=self.user_name).exists():
|
||||
self.stdout.write("Sahkopiikki user already exists. Skipping.")
|
||||
user = User.objects.get(username=self.user_name)
|
||||
token = Token.objects.get(user=user)
|
||||
self.stdout.write("Token: {}".format(token))
|
||||
return
|
||||
|
||||
u = User(username=self.user_name)
|
||||
u.set_password(self.password)
|
||||
|
||||
u.save()
|
||||
|
||||
permission = Permission.objects.get(codename='check_by_email')
|
||||
u.user_permissions.add(permission)
|
||||
|
||||
token = Token.objects.create(user=u)
|
||||
|
||||
self.stdout.write("Created sahkopiikki user '{}' with password '{}' and token '{}'.".format(
|
||||
self.user_name, self.password, token
|
||||
))
|
||||
@@ -3,8 +3,7 @@
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.db.models import Q, F, OuterRef, Subquery
|
||||
import csv
|
||||
from django.db.models import Q, OuterRef, Subquery
|
||||
|
||||
|
||||
class BaseMember(models.Model):
|
||||
@@ -124,11 +123,8 @@ class Member(BaseMember):
|
||||
qs = qs.filter(Q(first_name__icontains=term) | Q(last_name__icontains=term))
|
||||
return qs
|
||||
|
||||
@staticmethod
|
||||
def get_members_with_latest_payment(members_query):
|
||||
"""Return QuerySet of given members QS with last_paid attribute."""
|
||||
latest = Payment.objects.filter(member=OuterRef('pk')).order_by('-date')
|
||||
return members_query.annotate(last_paid=Subquery(latest.values('date')[:1]))
|
||||
|
||||
|
||||
# To avoid problems with a cyclical import, this is at the bottom of the file
|
||||
from members.forms import MemberForm # nopep8
|
||||
|
||||
@@ -35,5 +35,6 @@
|
||||
<body>
|
||||
{% block content %}
|
||||
{% endblock content %}
|
||||
{% include "webapp:footer.html" %}
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -6,5 +6,6 @@
|
||||
{% block content %}
|
||||
<link rel="stylesheet" href="{% static "css/application.css" %}">
|
||||
<h3>{% trans "Hienoa! Jäsenhakemuksesi on nyt lähetetty." %}</h3>
|
||||
<p>{% trans "Vahvistusviesti on lähetetty sähköpostiisi. Ota yhteyttä sik-vtmk@list.ayy.fi jos viestiä ei näy." %}</p>
|
||||
<a href="/"><h4>{% trans "Takaisin Sähköinsinöörikillan web-sivuille" %}</h4></a>
|
||||
{% endblock content %}
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
{% load i18n %}
|
||||
{% trans "Moi" %} {{ first_name }}!
|
||||
|
||||
{% trans "Onnittelut! Sinut on hyväksytty Sähköinsinöörikillan jäseneksi." %}
|
||||
|
||||
{% trans "Käy kurkkaamassa killan nettisivuilta" %} (https://sik.ayy.fi) {% trans "tulevia tapahtumia ja piipahda kiltahuoneella tutustumassa uusiin kiltatovereihisi!" %}
|
||||
|
||||
{% trans "Liity myös killan TG-kanaville" %}:
|
||||
{% trans "SIK" %}: https://t.me/joinchat/A6EViD5FCWLxPcXCggY7hw
|
||||
{% trans "SIK-fuksit 2019" %}: http://tinyurl.com/sikfuksit19-tg
|
||||
{% trans "SIK-fuksit 2019 -tiedotuskanava" %}: http://tinyurl.com/sikfuksit19-tiedotus
|
||||
@@ -0,0 +1,21 @@
|
||||
{% load i18n %}
|
||||
{% trans "Moikka" %} {{ application.first_name }},
|
||||
|
||||
{% trans "Sait tämän viestin, sillä olet lähettänyt hakemuksen Aalto-yliopiston Sähköinsinöörikillan jäseneksi alla olevin tiedoin. Siistiä!" %}
|
||||
|
||||
{% trans "Etunimi" %}: {{ application.first_name }}
|
||||
{% trans "Sukunimi" %}: {{ application.last_name }}
|
||||
{% trans "Sähköposti" %}: {{ application.email }}
|
||||
{% trans "Kotipaikkakunta" %}: {{ application.POR }}
|
||||
{% trans "AYY:n jäsen" %}: {{ ayy }}
|
||||
{% trans "Haluan jäsenmailin" %}: {{ jas }}
|
||||
|
||||
{% trans "Saat sähköpostiisi tiedon, kun sinut on hallituksen kokouksessa hyväksytty jäseneksi" %}.
|
||||
|
||||
{% trans "Muistathan maksaa jäsenmaksun! Alla maksutiedot" %}:
|
||||
|
||||
{% trans "Saaja" %}: Aalto-yliopiston Sähköinsinöörikilta ry
|
||||
{% trans "Tilinumero" %}: FI97 1309 3000 1118 23
|
||||
BIC: NDEAFIHH
|
||||
{% trans "Viite" %}: 1313
|
||||
{% trans "Summa" %}: 8 €
|
||||
@@ -3,7 +3,6 @@
|
||||
from django.test import TestCase, Client
|
||||
from unittest import skip
|
||||
from django.contrib.auth.models import User
|
||||
from members.management.commands.createsahkopiikkiuser import Command as SahkopiikkiCommand
|
||||
from members.models import Member, Payment, Request
|
||||
from rest_framework.authtoken.models import Token
|
||||
|
||||
@@ -31,9 +30,6 @@ class MemberRegisterTestCase(TestCase):
|
||||
self.c = Client()
|
||||
self.c.login(username=username, password=password)
|
||||
|
||||
sc = SahkopiikkiCommand()
|
||||
sc.handle()
|
||||
|
||||
def test_member_created(self):
|
||||
"""Test member creation."""
|
||||
exists = Member.objects.filter(first_name="Tidus").exists()
|
||||
@@ -78,37 +74,6 @@ class MemberRegisterTestCase(TestCase):
|
||||
results = response.json()['results']
|
||||
self.assertEqual(len(results), 0)
|
||||
|
||||
def test_sahkopiikki_check_by_email_not_found(self):
|
||||
"""Test if sähköpiikki auth and search work"""
|
||||
email = 'teppo@tulppu.fi'
|
||||
wrong_email = 'asd@asd.fi'
|
||||
Member.objects.create(email=email, first_name='Teppo', last_name='Tulppu')
|
||||
token = Token.objects.get(user__username='sahkopiikki').key
|
||||
self.c.defaults['HTTP_AUTHORIZATION'] = 'Token ' + token
|
||||
|
||||
response = self.c.get('/members/check?email={}'.format(wrong_email), follow=True)
|
||||
self.assertEqual(response.json()['exists'], False)
|
||||
|
||||
def test_sahkopiikki_check_by_email_found(self):
|
||||
"""Test if sähköpiikki auth and search work"""
|
||||
email = 'teppo@tulppu.fi'
|
||||
Member.objects.create(email=email, first_name='Teppo', last_name='Tulppu')
|
||||
token = Token.objects.get(user__username='sahkopiikki').key
|
||||
self.c.defaults['HTTP_AUTHORIZATION'] = 'Token ' + token
|
||||
|
||||
response = self.c.get('/members/check?email={}'.format(email), follow=True)
|
||||
self.assertEqual(response.json()['exists'], True)
|
||||
|
||||
def test_sahkopiikki_check_by_email_forbidden(self):
|
||||
"""Test if sähköpiikki auth and search work"""
|
||||
email = 'teppo@tulppu.fi'
|
||||
Member.objects.create(email=email, first_name='Teppo', last_name='Tulppu')
|
||||
token = Token.objects.get(user__username='sahkopiikki').key
|
||||
self.c.defaults['HTTP_AUTHORIZATION'] = 'Token ' + token + 'DERP'
|
||||
|
||||
response = self.c.get('/members/check?email={}'.format(email), follow=True)
|
||||
self.assertEqual(response.status_code, 401)
|
||||
|
||||
def test_export_members_excel(self):
|
||||
"""Test if the user can download an excel file of the member register"""
|
||||
resp = self.c.get('/members/export_members')
|
||||
|
||||
@@ -1,59 +1,4 @@
|
||||
"""File containing Members application views."""
|
||||
|
||||
from django.shortcuts import render
|
||||
from django.contrib.auth.decorators import permission_required
|
||||
from django.views.decorators.http import require_http_methods
|
||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.core.mail import send_mail
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.forms.models import model_to_dict
|
||||
|
||||
# Email validation
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
from django.utils.http import urlsafe_base64_encode
|
||||
from django.utils.encoding import force_bytes
|
||||
|
||||
import json
|
||||
import requests
|
||||
import logging
|
||||
import html
|
||||
import csv
|
||||
import pickle
|
||||
from smtplib import SMTPAuthenticationError
|
||||
|
||||
from members.models import Member, Request, Payment
|
||||
from members.forms import MemberForm, PaymentForm, ApplicationForm, CSVValidationError
|
||||
from members.views.utils import send_mail_wrapper
|
||||
|
||||
|
||||
@receiver(post_save, sender=Request)
|
||||
def email_on_request(sender, instance, created, **kwargs):
|
||||
"""Send email validation."""
|
||||
if not settings.ENABLE_AUTOMATIC_EMAILS:
|
||||
return
|
||||
|
||||
try:
|
||||
if created:
|
||||
subject = 'Test1'
|
||||
message = 'Please validate your email address\r\n'
|
||||
send_mail_wrapper(subject, message, instance.email)
|
||||
except SMTPAuthenticationError:
|
||||
logging.error('Failed to send email to accepted request!')
|
||||
|
||||
|
||||
@receiver(post_save, sender=Member)
|
||||
def email_on_accept(sender, instance, created, **kwargs):
|
||||
"""Send email to accepted member."""
|
||||
if not settings.ENABLE_AUTOMATIC_EMAILS:
|
||||
return
|
||||
|
||||
try:
|
||||
if created:
|
||||
subject = 'Test2'
|
||||
message = 'Jäsenhakemuksesi on hyväksytty!!!\r\n'
|
||||
send_mail_wrapper(subject, message, instance.email)
|
||||
except SMTPAuthenticationError:
|
||||
logging.error('Failed to send email to accepted member!')
|
||||
|
||||
@@ -3,14 +3,16 @@ from django.contrib.auth.decorators import permission_required, login_required
|
||||
from django.views.decorators.http import require_http_methods
|
||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.core.mail import send_mail
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.forms.models import model_to_dict
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
import logging
|
||||
import html
|
||||
|
||||
from webapp.utils import send_email
|
||||
|
||||
from members.views.utils import *
|
||||
from members.tables import RequestTable
|
||||
from members.forms import ApplicationForm
|
||||
@@ -90,6 +92,16 @@ def application_accept(request, *args, **kwargs):
|
||||
.format(form))
|
||||
notification = "{} {}.".format(_("Successfully accepted application"),
|
||||
str(application))
|
||||
|
||||
subject = _('Jäsenhakemuksesi Sähköinsinöörikiltaan on hyväksytty!')
|
||||
|
||||
message = render_to_string(
|
||||
'members:email_application_accept.html', {
|
||||
'first_name': application.first_name
|
||||
}
|
||||
)
|
||||
send_email(member.email, subject, message)
|
||||
|
||||
return HttpResponseRedirect(
|
||||
'/members/list?notification={}'.format(html.escape(notification)))
|
||||
except Exception as ex:
|
||||
@@ -152,13 +164,26 @@ def application_form(request, *args, **kwargs):
|
||||
|
||||
@ensure_csrf_cookie
|
||||
@require_http_methods(["POST"])
|
||||
@login_required(login_url='/admin/login')
|
||||
@permission_required('members.delete_request', raise_exception=True)
|
||||
def application_submit(request, *args, **kwargs):
|
||||
"""Submit member application"""
|
||||
form = ApplicationForm(request.POST)
|
||||
if form.is_valid():
|
||||
form.save()
|
||||
return render(request, 'application_success.html', {})
|
||||
try:
|
||||
application = form.instance
|
||||
email = form.cleaned_data.get('email', '')
|
||||
|
||||
subject = _('Jäsenhakemuksesi Sähköinsinöörikiltaan on lähetetty onnistuneesti!')
|
||||
|
||||
message = render_to_string(
|
||||
'members:email_application_submit.html', {
|
||||
'application': application,
|
||||
'ayy': _('Kyllä') if application.AYY else _('Ei'),
|
||||
'jas': _('Kyllä') if application.jas else _('Ei')
|
||||
}
|
||||
)
|
||||
send_email(email, subject, message)
|
||||
finally:
|
||||
return render(request, 'application_success.html', {})
|
||||
else:
|
||||
return error_view(request, form.errors)
|
||||
|
||||
@@ -4,7 +4,6 @@ from django.utils.decorators import method_decorator
|
||||
from django.views.decorators.http import require_http_methods
|
||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
from django.http import HttpResponse, HttpResponseRedirect, JsonResponse, HttpResponseForbidden
|
||||
from django.core.mail import send_mail
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.forms.models import model_to_dict
|
||||
|
||||
@@ -3,7 +3,6 @@ from django.contrib.auth.decorators import permission_required, login_required
|
||||
from django.views.decorators.http import require_http_methods
|
||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
from django.http import HttpResponse, HttpResponseRedirect
|
||||
from django.core.mail import send_mail
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.forms.models import model_to_dict
|
||||
|
||||
@@ -3,7 +3,6 @@ from django.contrib.auth.decorators import permission_required, login_required
|
||||
from django.views.decorators.http import require_http_methods
|
||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
from django.http import HttpResponse, HttpResponseRedirect, HttpResponseBadRequest
|
||||
from django.core.mail import send_mail
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.forms.models import model_to_dict
|
||||
@@ -145,15 +144,6 @@ def import_csv(request, *args, **kwargs):
|
||||
return render(request, 'member_add_many_confirm.html', context)
|
||||
|
||||
|
||||
def send_mail_wrapper(subject, message, email_to):
|
||||
"""Send mail to default email."""
|
||||
send_mail(subject,
|
||||
message,
|
||||
settings.DEFAULT_EMAIL_FROM,
|
||||
[email_to],
|
||||
fail_silently=False)
|
||||
|
||||
|
||||
def make_excel_response(Resource):
|
||||
res = Resource()
|
||||
dataset = res.export()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
html, body {
|
||||
background: #fdd504;
|
||||
background: linear-gradient(#fdaa02, #fdd504) no-repeat center center fixed;
|
||||
background: linear-gradient(#fcf4de, #fcf4de) no-repeat center center fixed;
|
||||
}
|
||||
|
||||
body {
|
||||
@@ -49,7 +49,7 @@ h3 {
|
||||
|
||||
.navbar {
|
||||
border-radius: 8px;
|
||||
background-color: #c1272d;
|
||||
background-color: #a87538;
|
||||
box-shadow: 0 0;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
border-radius: 8px;
|
||||
padding: 10px 15px 10px 15px;
|
||||
margin: 5px;
|
||||
background-color: #fdaa02;
|
||||
background-color: #fcf4de;
|
||||
}
|
||||
|
||||
a.nav-item.nav-link:hover {
|
||||
background-color: #fc8606;
|
||||
background-color: #ecc155;
|
||||
}
|
||||
|
||||
|
Before Width: | Height: | Size: 41 KiB After Width: | Height: | Size: 227 KiB |
@@ -14,6 +14,7 @@ from django.template.loader import render_to_string
|
||||
import logging
|
||||
import requests
|
||||
from dealer.git import git
|
||||
from sikweb.settings import URL
|
||||
|
||||
from ohlhafv.models import OhlhafvChallenge
|
||||
from ohlhafv.forms import OhlhafvForm
|
||||
@@ -39,7 +40,7 @@ def ohlhafv_submit(request, *args, **kwargs):
|
||||
challenge = form.instance
|
||||
email = form.cleaned_data.get('victim_email', '')
|
||||
|
||||
url = 'https://sika.sahkoinsinoorikilta.fi/ohlhafv/list'
|
||||
url = f'https://{URL}/ohlhafv/list'
|
||||
subject = _('Sinut on haastettu Øhlhäfviin!')
|
||||
|
||||
message = render_to_string(
|
||||
|
||||
@@ -3,20 +3,26 @@
|
||||
"version": "1.0.0",
|
||||
"description": "A modern web app using a Django backend and an Angular frontend.",
|
||||
"scripts": {
|
||||
"test": "eslint . && remark .",
|
||||
"eslint": "eslint .",
|
||||
"remark": "remark ."
|
||||
"lint": "run-p lint:js lint:md lint:py",
|
||||
"lint:js": "eslint .",
|
||||
"lint:md": "remark .",
|
||||
"lint:py": "pycodestyle --config=pycodestyle.cfg --count .",
|
||||
"lint:py-type": "pyright",
|
||||
"prepare": "husky install"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git@sika.sahkoinsinoorikilta.fi:vtmk/web2.0.git"
|
||||
"url": "git@gitlab.com:sahkoinsinoorikilta/vtmk/web2.0-backend.git"
|
||||
},
|
||||
"author": "SIK ry",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"eslint": "3.19.0",
|
||||
"remark-cli": "^4.0.0",
|
||||
"remark-preset-lint-recommended": "^3.0.1"
|
||||
"eslint": "^7.23.0",
|
||||
"husky": "^5.2.0",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"pyright": "^1.1.126",
|
||||
"remark-cli": "^9.0.0",
|
||||
"remark-preset-lint-recommended": "^5.0.0"
|
||||
},
|
||||
"remarkConfig": {
|
||||
"plugins": [
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
#!/bin/sh
|
||||
|
||||
# Get ENVs from secrets
|
||||
if test -f "$SECRET_KEY_FILE"; then
|
||||
export SECRET_KEY=$(cat $SECRET_KEY_FILE)
|
||||
fi
|
||||
if test -f "$TG_BOT_TOKEN_FILE"; then
|
||||
export TG_BOT_TOKEN=$(cat $TG_BOT_TOKEN_FILE)
|
||||
fi
|
||||
if test -f "$EMAIL_API_KEY_FILE"; then
|
||||
export EMAIL_API_KEY=$(cat $EMAIL_API_KEY_FILE)
|
||||
fi
|
||||
if test -f "$EMAIL_API_SECRET_FILE"; then
|
||||
export EMAIL_API_SECRET=$(cat $EMAIL_API_SECRET_FILE)
|
||||
fi
|
||||
if test -f "$DB_USER_FILE"; then
|
||||
export DB_USER=$(cat $DB_USER_FILE)
|
||||
fi
|
||||
if test -f "$DB_PASSWD_FILE"; then
|
||||
export DB_PASSWD=$(cat $DB_PASSWD_FILE)
|
||||
fi
|
||||
|
||||
# Collect static files
|
||||
echo "Collect static files"
|
||||
python manage.py collectstatic --noinput
|
||||
|
||||
# Apply database migrations
|
||||
echo "Apply database migrations"
|
||||
python manage.py migrate
|
||||
|
||||
# Start server
|
||||
echo "Django running on http://localhost:8000 in production mode"
|
||||
gunicorn -w 4 -b 0.0.0.0:8000 sikweb.wsgi
|
||||
@@ -1,4 +1,4 @@
|
||||
[pycodestyle]
|
||||
max-line-length = 120
|
||||
ignore = E501,E722
|
||||
exclude = '*/migrations/*', venv/*
|
||||
exclude = '*/migrations/*', venv/*, .venv/*
|
||||
@@ -0,0 +1,60 @@
|
||||
[tool.poetry]
|
||||
name = "web2.0-backend"
|
||||
version = "0.1.0"
|
||||
description = ""
|
||||
authors = ["Your Name <you@example.com>"]
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.9"
|
||||
Pillow = "^8.1.2"
|
||||
"backports.shutil_get_terminal_size" = "1.0.0"
|
||||
decorator = "4.0.9"
|
||||
Django = "2.1.5"
|
||||
ipython = "4.2.0"
|
||||
ipython_genutils = "0.1.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"
|
||||
PyJWT = "1.6.4"
|
||||
djangorestframework-jwt = "1.11.0"
|
||||
coverage = "4.3.4"
|
||||
django-nose = "1.4.5"
|
||||
nose-exclude = "0.5.0"
|
||||
psycopg2-binary = "2.8.4"
|
||||
django-bootstrap3 = "11.1.0"
|
||||
django-tables2 = "1.6.1"
|
||||
pycodestyle = "2.6.0"
|
||||
dealer = "2.0.5"
|
||||
django-modeltranslation = "0.13b1"
|
||||
django-auditlog = "0.4.5"
|
||||
phonenumbers = "8.11.4"
|
||||
django-phonenumber-field = {version = "4.0.0", extras = ["phonenumbers"]}
|
||||
django-autocomplete-light = "3.4.1"
|
||||
six = "1.12.0"
|
||||
django-suit = "0.2.26"
|
||||
telepot = "12.3"
|
||||
pyexcel = "0.5.14"
|
||||
pyexcel-xlsx = "0.5.8"
|
||||
django-import-export = "0.7.0"
|
||||
openpyxl = "2.6.4"
|
||||
django-app-namespace-template-loader = "0.4.1"
|
||||
django-filter = "2.0.0"
|
||||
whitenoise = "4.1.4"
|
||||
jsonschema = "3.2.0"
|
||||
mailjet-rest = "1.3.3"
|
||||
Markdown = "3.2.2"
|
||||
uWSGI = "2.0.18"
|
||||
gunicorn = "19.9.0"
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
@@ -0,0 +1,16 @@
|
||||
{
|
||||
"include": [
|
||||
"."
|
||||
],
|
||||
|
||||
"exclude": [
|
||||
"**/node_modules",
|
||||
"**/__pycache__"
|
||||
],
|
||||
"venvPath": "./venv",
|
||||
|
||||
"reportMissingImports": true,
|
||||
"reportMissingTypeStubs": false,
|
||||
|
||||
"pythonVersion": "3.7.4"
|
||||
}
|
||||
@@ -16,10 +16,6 @@ Data table app for viewing and modifying the member register, member application
|
||||
|
||||
Mostly static website with an event calendar and news feed.
|
||||
|
||||
### Coffee scale
|
||||
|
||||
Shows the current coffee scale status.
|
||||
|
||||
## Accessing the source
|
||||
|
||||
### Clone this repository and enter it
|
||||
@@ -98,7 +94,7 @@ Merge requests to `master` should be reviewed by multiple developers. Only a mod
|
||||
Lint python files using `pycodestyle` with
|
||||
|
||||
```bash
|
||||
pycodestyle --config=setup.cfg --count .
|
||||
pycodestyle --config=pycodestyle.cfg --count .
|
||||
```
|
||||
|
||||
Lint javascript and markdown using `eslint` and `remark` with
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
uWSGI==2.0.14
|
||||
uWSGI==2.0.18
|
||||
gunicorn==19.9.0
|
||||
|
||||
@@ -9,7 +9,7 @@ ptyprocess==0.5.1
|
||||
pytz==2016.4
|
||||
simplegeneric==0.8.1
|
||||
traitlets==4.2.1
|
||||
Pillow==5.4.1
|
||||
Pillow==7.2.0
|
||||
requests==2.11.1
|
||||
django-nocaptcha-recaptcha==0.0.19
|
||||
django-cors-headers==2.0.1
|
||||
@@ -19,21 +19,26 @@ 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
|
||||
psycopg2-binary==2.8.4
|
||||
django-bootstrap3==11.1.0
|
||||
django-tables2==1.6.1
|
||||
pycodestyle==2.3.1
|
||||
pycodestyle==2.6.0
|
||||
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
|
||||
phonenumbers==8.11.4
|
||||
django-phonenumber-field[phonenumbers]==4.0.0
|
||||
django-autocomplete-light==3.4.1
|
||||
six==1.12.0
|
||||
django-suit==0.2.26
|
||||
telepot==12.3
|
||||
pyexcel==0.5.10
|
||||
pyexcel-xlsx==0.5.5
|
||||
pyexcel==0.5.14
|
||||
pyexcel-xlsx==0.5.8
|
||||
django-import-export==0.7.0
|
||||
openpyxl==2.4.11
|
||||
openpyxl==2.6.4
|
||||
django-app-namespace-template-loader==0.4.1
|
||||
django-filter==2.0.0
|
||||
whitenoise==4.1.4
|
||||
jsonschema==3.2.0
|
||||
mailjet-rest==1.3.3
|
||||
markdown==3.2.2
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
echo "SIK WEB 2.0"
|
||||
echo "This script will set up the environment for this project."
|
||||
echo "========================================================="
|
||||
echo "Dependencies: python>3.5"
|
||||
echo "Dependencies: python3.7"
|
||||
|
||||
INTERACTIVE="true"
|
||||
USE_NPM="true"
|
||||
@@ -36,14 +36,6 @@ then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
$INTERACTIVE && read -p "Copy settings from template? (recommended) [y/n]" -n 1 -r || REPLY="y"
|
||||
echo ""
|
||||
|
||||
if [[ $REPLY =~ ^[Yy]$ ]]
|
||||
then
|
||||
cp "$PWD/sikweb/settings-sample.py" "$PWD/sikweb/settings.py"
|
||||
fi
|
||||
|
||||
$INTERACTIVE && read -p "Copy pre-push hook to .git/hooks? (recommended) [y/n]" -n 1 -r || REPLY="y"
|
||||
echo ""
|
||||
|
||||
@@ -65,6 +57,7 @@ fi
|
||||
set -e
|
||||
set -x
|
||||
pip install -r requirements.txt
|
||||
pip install -r requirements.production.txt
|
||||
$USE_NPM && npm install
|
||||
python manage.py migrate
|
||||
python manage.py createdefaultadmin
|
||||
|
||||
@@ -1,14 +0,0 @@
|
||||
"""File containing CI settings."""
|
||||
|
||||
from sikweb.default_settings import *
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||
'NAME': 'ci',
|
||||
'USER': 'postgres',
|
||||
'PASSWORD': 'postgres',
|
||||
'HOST': 'postgres',
|
||||
'PORT': '5432',
|
||||
},
|
||||
}
|
||||
@@ -7,19 +7,12 @@ from django.utils.translation import ugettext_lazy as _
|
||||
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
|
||||
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
|
||||
|
||||
IS_DOCKER = bool(os.getenv('IS_DOCKER', None))
|
||||
|
||||
# Quick-start development settings - unsuitable for production
|
||||
# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/
|
||||
|
||||
|
||||
SESSION_SERIALIZER = 'django.contrib.sessions.serializers.PickleSerializer'
|
||||
|
||||
if not IS_DOCKER:
|
||||
ALLOWED_HOSTS = []
|
||||
else:
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
|
||||
# Logger level
|
||||
|
||||
LOGGERLEVEL = logging.DEBUG
|
||||
@@ -93,7 +86,6 @@ INSTALLED_APPS = [
|
||||
'webapp',
|
||||
'members',
|
||||
'infoscreen',
|
||||
'coffee_scale',
|
||||
'kaehmy',
|
||||
'ohlhafv',
|
||||
'rest_framework',
|
||||
@@ -124,6 +116,7 @@ NOSE_ARGS = [
|
||||
MIDDLEWARE = [
|
||||
'sikweb.middleware.ForceDefaultLanguageMiddleware',
|
||||
'django.middleware.security.SecurityMiddleware',
|
||||
'whitenoise.middleware.WhiteNoiseMiddleware',
|
||||
'django.contrib.sessions.middleware.SessionMiddleware',
|
||||
'django.middleware.locale.LocaleMiddleware',
|
||||
'corsheaders.middleware.CorsMiddleware',
|
||||
@@ -134,9 +127,7 @@ MIDDLEWARE = [
|
||||
'django.middleware.clickjacking.XFrameOptionsMiddleware',
|
||||
'auditlog.middleware.AuditlogMiddleware'
|
||||
]
|
||||
MIDDLEWARE_CLASSES = [
|
||||
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
|
||||
]
|
||||
|
||||
CORS_ORIGIN_ALLOW_ALL = True
|
||||
|
||||
ROOT_URLCONF = 'sikweb.urls'
|
||||
@@ -166,36 +157,6 @@ TEMPLATES = [
|
||||
|
||||
WSGI_APPLICATION = 'sikweb.wsgi.application'
|
||||
|
||||
|
||||
# Database
|
||||
# https://docs.djangoproject.com/en/1.9/ref/settings/#databases
|
||||
|
||||
if not IS_DOCKER:
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||
'NAME': 'sik',
|
||||
'USER': 'sik',
|
||||
'PASSWORD': 'password123',
|
||||
'HOST': 'localhost',
|
||||
'PORT': '5432',
|
||||
'TEST': {
|
||||
'NAME': 'sik_test',
|
||||
},
|
||||
},
|
||||
}
|
||||
else:
|
||||
logging.info('Using docker database configuration')
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||
'NAME': 'postgres',
|
||||
'USER': 'postgres',
|
||||
'PASSWORD': 'postgres',
|
||||
'HOST': 'db',
|
||||
'PORT': '5432',
|
||||
},
|
||||
}
|
||||
# Password validation
|
||||
# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators
|
||||
|
||||
@@ -227,16 +188,16 @@ REST_FRAMEWORK = {
|
||||
'DEFAULT_AUTHENTICATION_CLASSES': (
|
||||
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
|
||||
),
|
||||
'DEFAULT_THROTTLE_CLASSES': (
|
||||
'members.throttles.BurstRateThrottle',
|
||||
'members.throttles.SustainedRateThrottle'
|
||||
),
|
||||
'DEFAULT_THROTTLE_RATES': {
|
||||
'burst': '60/min',
|
||||
'sustained': '1000/day'
|
||||
},
|
||||
# 'DEFAULT_THROTTLE_CLASSES': (
|
||||
# 'members.throttles.BurstRateThrottle',
|
||||
# 'members.throttles.SustainedRateThrottle'
|
||||
# ),
|
||||
# 'DEFAULT_THROTTLE_RATES': {
|
||||
# 'burst': '60/min',
|
||||
# 'sustained': '1000/day'
|
||||
# },
|
||||
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
|
||||
'PAGE_SIZE': 10,
|
||||
'PAGE_SIZE': 1000,
|
||||
'DEFAULT_FILTER_BACKENDS': (
|
||||
'django_filters.rest_framework.DjangoFilterBackend',
|
||||
),
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
|
||||
"""
|
||||
Django settings for sikweb project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 1.9.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/1.9/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/1.9/ref/settings/
|
||||
"""
|
||||
|
||||
from sikweb.base import *
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = True
|
||||
|
||||
# ALLOWED_HOSTS = ["*"]
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = '7p$85^4ibb^p4-=vs44b7!y0e-zemugze18@a#30&71=a8)dp('
|
||||
|
||||
# MQTT settings
|
||||
MQTT_SETTINGS = {
|
||||
'HOST': 'mqtt.sik.party',
|
||||
'PORT': 1883,
|
||||
'TOPICS': {
|
||||
'BREW_TIME': 'sik/kiltahuone/kahvivaaka/brewtime',
|
||||
'WEIGHT': 'sik/kiltahuone/kahvivaaka/weight',
|
||||
'BREWING': 'sik/kiltahuone/kahvivaaka/brewing',
|
||||
'CUPS': 'sik/kiltahuone/kahvivaaka/cups',
|
||||
}
|
||||
}
|
||||
|
||||
# ReCaptcha
|
||||
# http://www.yaconiello.com/blog/integrating-google-recaptcha-to-django/
|
||||
GOOGLE_RECAPTCHA_SITE_KEY = "YOUR-PUBLIC-KEY"
|
||||
GOOGLE_RECAPTCHA_SECRET_KEY = "YOUR-PRIVATE-KEY"
|
||||
|
||||
# Email settings (more settings in base.py)
|
||||
EMAIL_HOST_USER = '<gmailtunnarisi>@gmail.com'
|
||||
EMAIL_HOST_PASSWORD = '<gmail_passu>'
|
||||
DEFAULT_EMAIL_FROM = 'SIK Viestintä <sikviestinta@gmail.com>'
|
||||
ENABLE_AUTOMATIC_EMAILS = False
|
||||
|
||||
# Token for Telegram bot
|
||||
TELEGRAM_BOT_TOKEN = "<BOT_TOKEN>"
|
||||
|
||||
# Database settings
|
||||
# Only uncomment if default settings in base.py are not ok
|
||||
|
||||
# DATABASES = {
|
||||
# 'default': {
|
||||
# 'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||
# 'NAME': 'sik',
|
||||
# 'USER': 'sik',
|
||||
# 'PASSWORD': 'password123',
|
||||
# 'HOST': 'localhost',
|
||||
# 'PORT': '5432',
|
||||
# 'TEST': {
|
||||
# 'NAME': 'sik_test',
|
||||
# },
|
||||
# },
|
||||
# }
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.sqlite3',
|
||||
'NAME': 'mydatabase',
|
||||
'TEST': {
|
||||
'NAME': 'sik_test',
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
|
||||
"""
|
||||
Django settings for sikweb project.
|
||||
|
||||
Generated by 'django-admin startproject' using Django 1.9.
|
||||
|
||||
For more information on this file, see
|
||||
https://docs.djangoproject.com/en/1.9/topics/settings/
|
||||
|
||||
For the full list of settings and their values, see
|
||||
https://docs.djangoproject.com/en/1.9/ref/settings/
|
||||
"""
|
||||
|
||||
from sikweb.base import *
|
||||
|
||||
# SECURITY WARNING: don't run with debug turned on in production!
|
||||
DEBUG = os.getenv('DEBUG', False) == 'True'
|
||||
|
||||
URL = os.getenv("HOST", "api.sahkoinsinoorikilta.fi")
|
||||
FRONTEND_URL = os.getenv("FRONTEND_URL", "sahkoinsinoorikilta.fi")
|
||||
ALLOWED_HOSTS = ["localhost", "127.0.0.1", FRONTEND_URL, URL]
|
||||
if DEBUG:
|
||||
ALLOWED_HOSTS = ["*"]
|
||||
|
||||
USE_X_FORWARDED_HOST = True
|
||||
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
|
||||
|
||||
# SECURITY WARNING: keep the secret key used in production secret!
|
||||
SECRET_KEY = os.getenv('SECRET_KEY', '7p$85^4ibb^p4-=vs44b7!y0e-zemugze18@a#30&71=a8)dp(')
|
||||
|
||||
# ReCaptcha
|
||||
# http://www.yaconiello.com/blog/integrating-google-recaptcha-to-django/
|
||||
GOOGLE_RECAPTCHA_SITE_KEY = os.getenv("GOOGLE_RECAPTCHA_SITE_KEY", "YOUR-PUBLIC-KEY")
|
||||
GOOGLE_RECAPTCHA_SECRET_KEY = os.getenv("GOOGLE_RECAPTCHA_SECRET_KEY", "YOUR-PRIVATE-KEY")
|
||||
|
||||
# Email settings (more settings in base.py)
|
||||
EMAIL_API_KEY = os.getenv('EMAIL_API_KEY', '')
|
||||
EMAIL_API_SECRET = os.getenv('EMAIL_API_SECRET', '')
|
||||
DEFAULT_EMAIL_FROM = 'SIK'
|
||||
DEFAULT_EMAIL_FROM_ADDR = 'noreply@sahkoinsinoorikilta.fi'
|
||||
ENABLE_AUTOMATIC_EMAILS = True
|
||||
|
||||
# Token for Telegram bot
|
||||
TELEGRAM_BOT_TOKEN = os.getenv('TG_BOT_TOKEN', '<tg token>')
|
||||
|
||||
# Database settings
|
||||
# Only uncomment if default settings in base.py are not ok
|
||||
|
||||
DATABASES = {
|
||||
'default': {
|
||||
'ENGINE': 'django.db.backends.postgresql_psycopg2',
|
||||
'NAME': os.getenv('DB_USER', 'postgres'),
|
||||
'USER': os.getenv('DB_USER', 'postgres'),
|
||||
'PASSWORD': os.getenv('DB_PASSWD', 'postgres'),
|
||||
'HOST': os.getenv('DB_HOST', 'localhost'),
|
||||
'PORT': os.getenv('DB_PORT', 5432),
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,6 @@ from django.views.generic.base import RedirectView
|
||||
import webapp.urls
|
||||
import infoscreen.urls
|
||||
import members.urls
|
||||
import coffee_scale.urls
|
||||
|
||||
favicon_view = RedirectView.as_view(
|
||||
url='static/img/favicon.png', permanent=True)
|
||||
@@ -36,7 +35,6 @@ urlpatterns = [
|
||||
url(r'', include('webapp.urls')),
|
||||
url(r'^members/', include('members.urls')),
|
||||
url(r'^infoscreen/', include('infoscreen.urls')),
|
||||
url(r'^coffee/', include('coffee_scale.urls')),
|
||||
url(r'^kaehmy/', include('kaehmy.urls')),
|
||||
url(r'^ohlhafv/', include('ohlhafv.urls')),
|
||||
|
||||
|
||||
@@ -0,0 +1,45 @@
|
||||
version: '3.4'
|
||||
services:
|
||||
db:
|
||||
image: postgres:12
|
||||
deploy:
|
||||
replicas: 1
|
||||
environment:
|
||||
- POSTGRES_PASSWORD=postgres
|
||||
ports:
|
||||
- 5432:5432
|
||||
volumes:
|
||||
- dbdata:/var/lib/postgresql/data
|
||||
|
||||
backend:
|
||||
image: registry.gitlab.com/sahkoinsinoorikilta/vtmk/web2.0-backend:latest
|
||||
deploy:
|
||||
replicas: 1
|
||||
update_config:
|
||||
order: start-first
|
||||
depends_on:
|
||||
- db
|
||||
ports:
|
||||
- 8000:8000
|
||||
|
||||
environment:
|
||||
- HOST=api.dev.sahkoinsinoorikilta.fi
|
||||
- FRONTEND_URL=dev.sahkoinsinoorikilta.fi
|
||||
- DEBUG=True
|
||||
- EMAIL_API_KEY_FILE=/run/secrets/DJANGO_EMAIL_API_KEY
|
||||
- EMAIL_API_SECRET_FILE=/run/secrets/DJANGO_EMAIL_API_SECRET
|
||||
- DB_HOST=db
|
||||
- DB_PORT=5432
|
||||
|
||||
secrets:
|
||||
- DJANGO_EMAIL_API_KEY
|
||||
- DJANGO_EMAIL_API_SECRET
|
||||
|
||||
secrets:
|
||||
DJANGO_EMAIL_API_KEY:
|
||||
external: true
|
||||
DJANGO_EMAIL_API_SECRET:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
dbdata:
|
||||
@@ -0,0 +1,76 @@
|
||||
version: '3.4'
|
||||
services:
|
||||
db:
|
||||
image: postgres:12
|
||||
deploy:
|
||||
replicas: 1
|
||||
|
||||
environment:
|
||||
- POSTGRES_USER_FILE=/run/secrets/BACKEND_DB_USER
|
||||
- POSTGRES_PASSWORD_FILE=/run/secrets/BACKEND_DB_PASSWD
|
||||
ports:
|
||||
- 5432:5432
|
||||
volumes:
|
||||
- dbdata:/var/lib/postgresql/data
|
||||
secrets:
|
||||
- BACKEND_DB_USER
|
||||
- BACKEND_DB_PASSWD
|
||||
|
||||
backend:
|
||||
image: registry.gitlab.com/sahkoinsinoorikilta/vtmk/web2.0-backend:latest
|
||||
deploy:
|
||||
replicas: 1
|
||||
update_config:
|
||||
order: start-first
|
||||
depends_on:
|
||||
- db
|
||||
ports:
|
||||
- 8000:8000
|
||||
volumes:
|
||||
- type: bind
|
||||
source: /home/sik/production/files/static/.hidden/django/media
|
||||
target: /app/media
|
||||
- type: bind
|
||||
source: /home/sik/production/files/static/.hidden/django/static
|
||||
target: /app/static
|
||||
- type: bind
|
||||
source: /home/sik/production/files/static/.hidden/django/collected_static
|
||||
target: /app/collected_static
|
||||
|
||||
environment:
|
||||
- SECRET_KEY_FILE=/run/secrets/BACKEND_SECRET_KEY
|
||||
- TG_BOT_TOKEN_FILE=/run/secrets/BACKEND_TG_BOT_TOKEN
|
||||
- DB_USER_FILE=/run/secrets/BACKEND_DB_USER
|
||||
- DB_PASSWD_FILE=/run/secrets/BACKEND_DB_PASSWD
|
||||
- HOST=api.sahkoinsinoorikilta.fi
|
||||
- FRONTEND_URL=sahkoinsinoorikilta.fi
|
||||
- DB_HOST=db
|
||||
- DB_PORT=5432
|
||||
- EMAIL_API_KEY_FILE=/run/secrets/BACKEND_EMAIL_API_KEY
|
||||
- EMAIL_API_SECRET_FILE=/run/secrets/BACKEND_EMAIL_API_SECRET
|
||||
|
||||
secrets:
|
||||
- BACKEND_SECRET_KEY
|
||||
- BACKEND_TG_BOT_TOKEN
|
||||
- BACKEND_DB_USER
|
||||
- BACKEND_DB_PASSWD
|
||||
- BACKEND_EMAIL_API_KEY
|
||||
- BACKEND_EMAIL_API_SECRET
|
||||
secrets:
|
||||
BACKEND_SECRET_KEY:
|
||||
external: true
|
||||
BACKEND_TG_BOT_TOKEN:
|
||||
external: true
|
||||
BACKEND_DB_NAME:
|
||||
external: true
|
||||
BACKEND_DB_USER:
|
||||
external: true
|
||||
BACKEND_DB_PASSWD:
|
||||
external: true
|
||||
BACKEND_EMAIL_API_KEY:
|
||||
external: true
|
||||
BACKEND_EMAIL_API_SECRET:
|
||||
external: true
|
||||
|
||||
volumes:
|
||||
dbdata:
|
||||
|
Before Width: | Height: | Size: 192 KiB |
@@ -1,177 +0,0 @@
|
||||
#!/usr/bin/env bash
|
||||
# Use this script to test if a given TCP host/port are available
|
||||
|
||||
cmdname=$(basename $0)
|
||||
|
||||
echoerr() { if [[ $QUIET -ne 1 ]]; then echo "$@" 1>&2; fi }
|
||||
|
||||
usage()
|
||||
{
|
||||
cat << USAGE >&2
|
||||
Usage:
|
||||
$cmdname host:port [-s] [-t timeout] [-- command args]
|
||||
-h HOST | --host=HOST Host or IP under test
|
||||
-p PORT | --port=PORT TCP port under test
|
||||
Alternatively, you specify the host and port as host:port
|
||||
-s | --strict Only execute subcommand if the test succeeds
|
||||
-q | --quiet Don't output any status messages
|
||||
-t TIMEOUT | --timeout=TIMEOUT
|
||||
Timeout in seconds, zero for no timeout
|
||||
-- COMMAND ARGS Execute command with args after the test finishes
|
||||
USAGE
|
||||
exit 1
|
||||
}
|
||||
|
||||
wait_for()
|
||||
{
|
||||
if [[ $TIMEOUT -gt 0 ]]; then
|
||||
echoerr "$cmdname: waiting $TIMEOUT seconds for $HOST:$PORT"
|
||||
else
|
||||
echoerr "$cmdname: waiting for $HOST:$PORT without a timeout"
|
||||
fi
|
||||
start_ts=$(date +%s)
|
||||
while :
|
||||
do
|
||||
if [[ $ISBUSY -eq 1 ]]; then
|
||||
nc -z $HOST $PORT
|
||||
result=$?
|
||||
else
|
||||
(echo > /dev/tcp/$HOST/$PORT) >/dev/null 2>&1
|
||||
result=$?
|
||||
fi
|
||||
if [[ $result -eq 0 ]]; then
|
||||
end_ts=$(date +%s)
|
||||
echoerr "$cmdname: $HOST:$PORT is available after $((end_ts - start_ts)) seconds"
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
return $result
|
||||
}
|
||||
|
||||
wait_for_wrapper()
|
||||
{
|
||||
# In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692
|
||||
if [[ $QUIET -eq 1 ]]; then
|
||||
timeout $BUSYTIMEFLAG $TIMEOUT $0 --quiet --child --host=$HOST --port=$PORT --timeout=$TIMEOUT &
|
||||
else
|
||||
timeout $BUSYTIMEFLAG $TIMEOUT $0 --child --host=$HOST --port=$PORT --timeout=$TIMEOUT &
|
||||
fi
|
||||
PID=$!
|
||||
trap "kill -INT -$PID" INT
|
||||
wait $PID
|
||||
RESULT=$?
|
||||
if [[ $RESULT -ne 0 ]]; then
|
||||
echoerr "$cmdname: timeout occurred after waiting $TIMEOUT seconds for $HOST:$PORT"
|
||||
fi
|
||||
return $RESULT
|
||||
}
|
||||
|
||||
# process arguments
|
||||
while [[ $# -gt 0 ]]
|
||||
do
|
||||
case "$1" in
|
||||
*:* )
|
||||
hostport=(${1//:/ })
|
||||
HOST=${hostport[0]}
|
||||
PORT=${hostport[1]}
|
||||
shift 1
|
||||
;;
|
||||
--child)
|
||||
CHILD=1
|
||||
shift 1
|
||||
;;
|
||||
-q | --quiet)
|
||||
QUIET=1
|
||||
shift 1
|
||||
;;
|
||||
-s | --strict)
|
||||
STRICT=1
|
||||
shift 1
|
||||
;;
|
||||
-h)
|
||||
HOST="$2"
|
||||
if [[ $HOST == "" ]]; then break; fi
|
||||
shift 2
|
||||
;;
|
||||
--host=*)
|
||||
HOST="${1#*=}"
|
||||
shift 1
|
||||
;;
|
||||
-p)
|
||||
PORT="$2"
|
||||
if [[ $PORT == "" ]]; then break; fi
|
||||
shift 2
|
||||
;;
|
||||
--port=*)
|
||||
PORT="${1#*=}"
|
||||
shift 1
|
||||
;;
|
||||
-t)
|
||||
TIMEOUT="$2"
|
||||
if [[ $TIMEOUT == "" ]]; then break; fi
|
||||
shift 2
|
||||
;;
|
||||
--timeout=*)
|
||||
TIMEOUT="${1#*=}"
|
||||
shift 1
|
||||
;;
|
||||
--)
|
||||
shift
|
||||
CLI=("$@")
|
||||
break
|
||||
;;
|
||||
--help)
|
||||
usage
|
||||
;;
|
||||
*)
|
||||
echoerr "Unknown argument: $1"
|
||||
usage
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
if [[ "$HOST" == "" || "$PORT" == "" ]]; then
|
||||
echoerr "Error: you need to provide a host and port to test."
|
||||
usage
|
||||
fi
|
||||
|
||||
TIMEOUT=${TIMEOUT:-15}
|
||||
STRICT=${STRICT:-0}
|
||||
CHILD=${CHILD:-0}
|
||||
QUIET=${QUIET:-0}
|
||||
|
||||
# check to see if timeout is from busybox?
|
||||
# check to see if timeout is from busybox?
|
||||
TIMEOUT_PATH=$(realpath $(which timeout))
|
||||
if [[ $TIMEOUT_PATH =~ "busybox" ]]; then
|
||||
ISBUSY=1
|
||||
BUSYTIMEFLAG="-t"
|
||||
else
|
||||
ISBUSY=0
|
||||
BUSYTIMEFLAG=""
|
||||
fi
|
||||
|
||||
if [[ $CHILD -gt 0 ]]; then
|
||||
wait_for
|
||||
RESULT=$?
|
||||
exit $RESULT
|
||||
else
|
||||
if [[ $TIMEOUT -gt 0 ]]; then
|
||||
wait_for_wrapper
|
||||
RESULT=$?
|
||||
else
|
||||
wait_for
|
||||
RESULT=$?
|
||||
fi
|
||||
fi
|
||||
|
||||
if [[ $CLI != "" ]]; then
|
||||
if [[ $RESULT -ne 0 && $STRICT -eq 1 ]]; then
|
||||
echoerr "$cmdname: strict mode, refusing to execute subprocess"
|
||||
exit $RESULT
|
||||
fi
|
||||
exec "${CLI[@]}"
|
||||
else
|
||||
exit $RESULT
|
||||
fi
|
||||
@@ -1,8 +1,7 @@
|
||||
"""File containing webapp app admin registers."""
|
||||
|
||||
from django.contrib import admin
|
||||
from webapp.models import Official, Role, Committee
|
||||
from webapp.models import Feed, Tag, BaseFeed, Event, Signup, SignupForm, TemplateQuestion
|
||||
from webapp.models import Feed, Tag, Event, Signup, SignupForm, TemplateQuestion, JobAd
|
||||
from modeltranslation.admin import TranslationAdmin
|
||||
from django.contrib.auth.models import Permission
|
||||
# this is needed so that the models get registered for translation
|
||||
@@ -16,6 +15,4 @@ admin.site.register(Event, TranslationAdmin)
|
||||
admin.site.register(SignupForm, TranslationAdmin)
|
||||
admin.site.register(Signup, TranslationAdmin)
|
||||
admin.site.register(TemplateQuestion, TranslationAdmin)
|
||||
admin.site.register(Official)
|
||||
admin.site.register(Role)
|
||||
admin.site.register(Committee)
|
||||
admin.site.register(JobAd, TranslationAdmin)
|
||||
|
||||
@@ -10,4 +10,4 @@ class WebappConfig(AppConfig):
|
||||
|
||||
def ready(self):
|
||||
"""Import translations."""
|
||||
import webapp.translations
|
||||
import webapp.translation
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
"""File containing webapp forms."""
|
||||
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.core.exceptions import ValidationError
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 2.1.5 on 2019-09-26 17:48
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('webapp', '0054_auto_20190313_1642'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.DeleteModel(
|
||||
name='official'
|
||||
)
|
||||
]
|
||||
@@ -0,0 +1,58 @@
|
||||
# Generated by Django 2.1.5 on 2019-09-26 17:51
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
import phonenumber_field.modelfields
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
|
||||
('webapp', '0055_auto_20190926_2048'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='Occupation',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('start_date', models.DateField(verbose_name='Start date')),
|
||||
('end_date', models.DateField(verbose_name='End date')),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Occupation',
|
||||
'verbose_name_plural': 'Occupations',
|
||||
},
|
||||
),
|
||||
migrations.CreateModel(
|
||||
name='Official',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('first_name', models.CharField(max_length=30, verbose_name='First name')),
|
||||
('last_name', models.CharField(max_length=150, verbose_name='Last name')),
|
||||
('email', models.EmailField(max_length=254, verbose_name='Email address')),
|
||||
('phone_number', phonenumber_field.modelfields.PhoneNumberField(max_length=128, verbose_name='Phone number')),
|
||||
('role_history', models.ManyToManyField(blank=True, to='webapp.Occupation')),
|
||||
('user', models.OneToOneField(on_delete=django.db.models.deletion.CASCADE, to=settings.AUTH_USER_MODEL)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'Official',
|
||||
'verbose_name_plural': 'Officials',
|
||||
},
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='role',
|
||||
name='end_date',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='role',
|
||||
name='start_date',
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='occupation',
|
||||
name='role',
|
||||
field=models.OneToOneField(null=True, on_delete=django.db.models.deletion.SET_NULL, to='webapp.Role'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 2.1.5 on 2019-09-26 18:02
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.db.models.deletion
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('webapp', '0056_auto_20190926_2051'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='occupation',
|
||||
name='role',
|
||||
field=models.ForeignKey(null=True, on_delete=django.db.models.deletion.SET_NULL, to='webapp.Role'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 2.1.5 on 2019-10-10 15:37
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('webapp', '0057_auto_20190926_2102'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='official',
|
||||
name='role_history',
|
||||
field=models.ManyToManyField(blank=True, related_name='officials', to='webapp.Occupation'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,23 @@
|
||||
# Generated by Django 2.1.5 on 2019-10-10 16:00
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('webapp', '0058_auto_20191010_1837'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='committee',
|
||||
name='name_en',
|
||||
field=models.CharField(max_length=255, null=True, verbose_name='Name'),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='committee',
|
||||
name='name_fi',
|
||||
field=models.CharField(max_length=255, null=True, verbose_name='Name'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 2.1.5 on 2019-10-10 16:05
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('webapp', '0059_auto_20191010_1900'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='official',
|
||||
name='image',
|
||||
field=models.ImageField(null=True, upload_to=''),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,29 @@
|
||||
# Generated by Django 2.1.5 on 2019-11-10 18:24
|
||||
|
||||
import django.contrib.postgres.fields.jsonb
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('webapp', '0060_official_image'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='official',
|
||||
name='image',
|
||||
field=models.ImageField(blank=True, null=True, upload_to=''),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='signup',
|
||||
name='answer',
|
||||
field=django.contrib.postgres.fields.jsonb.JSONField(),
|
||||
),
|
||||
migrations.AlterField(
|
||||
model_name='signupform',
|
||||
name='questions',
|
||||
field=django.contrib.postgres.fields.jsonb.JSONField(),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 2.1.5 on 2019-11-10 19:17
|
||||
|
||||
import django.contrib.postgres.fields.jsonb
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('webapp', '0061_auto_20191110_2024'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='templatequestion',
|
||||
name='question',
|
||||
field=django.contrib.postgres.fields.jsonb.JSONField(),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 2.1.5 on 2020-06-16 18:48
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('webapp', '0062_auto_20191110_2117'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='signup',
|
||||
name='list_name',
|
||||
field=models.CharField(default='', max_length=255, verbose_name='Name'),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,19 @@
|
||||
# Generated by Django 2.1.5 on 2020-06-22 15:42
|
||||
|
||||
from django.db import migrations, models
|
||||
import uuid
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('webapp', '0063_signup_list_name'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='signup',
|
||||
name='uuid',
|
||||
field=models.UUIDField(default=uuid.uuid4, editable=False),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 2.1.5 on 2020-06-22 18:24
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('webapp', '0064_signup_uuid'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='signup',
|
||||
name='email',
|
||||
field=models.EmailField(blank=True, max_length=254, null=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 2.1.5 on 2020-06-22 20:02
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('webapp', '0065_signup_email'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='event',
|
||||
name='signupForm',
|
||||
field=models.ManyToManyField(blank=True, related_name='event', to='webapp.SignupForm'),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 2.1.5 on 2020-07-22 14:54
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('webapp', '0066_auto_20200622_2302'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='basefeed',
|
||||
name='image',
|
||||
field=models.ImageField(blank=True, null=True, upload_to=''),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 2.1.5 on 2020-07-22 17:47
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('webapp', '0067_basefeed_image'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='signupform',
|
||||
name='quota',
|
||||
field=models.PositiveIntegerField(blank=True, null=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,20 @@
|
||||
# Generated by Django 2.1.5 on 2020-07-23 19:18
|
||||
|
||||
import django.contrib.postgres.fields.jsonb
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('webapp', '0068_signupform_quota'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='signupform',
|
||||
name='schema',
|
||||
field=django.contrib.postgres.fields.jsonb.JSONField(default=[]),
|
||||
preserve_default=False,
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,39 @@
|
||||
# Generated by Django 2.1.5 on 2020-10-04 15:20
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('webapp', '0069_signupform_schema'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='event',
|
||||
name='location_en',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='event',
|
||||
name='location_fi',
|
||||
field=models.CharField(blank=True, max_length=255, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='signupform',
|
||||
name='email_content',
|
||||
field=models.TextField(default=''),
|
||||
preserve_default=False,
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='signupform',
|
||||
name='title_en',
|
||||
field=models.CharField(max_length=255, null=True),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='signupform',
|
||||
name='title_fi',
|
||||
field=models.CharField(max_length=255, null=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 2.1.5 on 2020-10-06 14:49
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('webapp', '0070_auto_20201004_1820'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterField(
|
||||
model_name='signupform',
|
||||
name='email_content',
|
||||
field=models.TextField(blank=True),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,38 @@
|
||||
# Generated by Django 2.1.5 on 2020-11-03 15:38
|
||||
|
||||
from django.db import migrations, models
|
||||
import django.utils.timezone
|
||||
import webapp.utils
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('webapp', '0071_auto_20201006_1749'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.CreateModel(
|
||||
name='JobAd',
|
||||
fields=[
|
||||
('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
|
||||
('title', models.CharField(max_length=255)),
|
||||
('title_fi', models.CharField(max_length=255, null=True)),
|
||||
('title_en', models.CharField(max_length=255, null=True)),
|
||||
('description', models.CharField(max_length=255)),
|
||||
('description_fi', models.CharField(max_length=255, null=True)),
|
||||
('description_en', models.CharField(max_length=255, null=True)),
|
||||
('content', models.TextField()),
|
||||
('content_fi', models.TextField(null=True)),
|
||||
('content_en', models.TextField(null=True)),
|
||||
('visible', models.BooleanField(default=True)),
|
||||
('created_at', models.DateTimeField(default=django.utils.timezone.now)),
|
||||
('autohide_at', models.DateTimeField(default=webapp.utils.month_from_now)),
|
||||
('autohide_enabled', models.BooleanField(default=False)),
|
||||
],
|
||||
options={
|
||||
'verbose_name': 'JobAd',
|
||||
'verbose_name_plural': 'JobAds',
|
||||
},
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,60 @@
|
||||
# Generated by Django 2.1.5 on 2020-11-07 17:16
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('webapp', '0072_jobad'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name='occupation',
|
||||
name='role',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='official',
|
||||
name='role_history',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='official',
|
||||
name='user',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='presetrole',
|
||||
name='baserole_ptr',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='role',
|
||||
name='committee',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='role',
|
||||
name='presetrole_ptr',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='baserole',
|
||||
name='name_en',
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='baserole',
|
||||
name='name_fi',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Committee',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Occupation',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Official',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='PresetRole',
|
||||
),
|
||||
migrations.DeleteModel(
|
||||
name='Role',
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,18 @@
|
||||
# Generated by Django 2.1.5 on 2020-11-07 18:00
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('webapp', '0073_auto_20201107_1916'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='signup',
|
||||
name='deleted',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
||||
@@ -0,0 +1,33 @@
|
||||
# Generated by Django 2.1.5 on 2021-01-14 19:55
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('webapp', '0074_signup_deleted'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AddField(
|
||||
model_name='event',
|
||||
name='deleted',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='feed',
|
||||
name='deleted',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='jobad',
|
||||
name='deleted',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name='signupform',
|
||||
name='deleted',
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
]
|
||||
@@ -1,33 +1,35 @@
|
||||
"""Webapp app models."""
|
||||
|
||||
from django.conf import settings
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
# from datetime import timedelta
|
||||
from django.contrib.auth.models import User
|
||||
from webapp.utils import month_from_now
|
||||
from django.db.models.signals import post_save
|
||||
from django.dispatch import receiver
|
||||
from webapp.utils import month_from_now, send_signup_email
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
# from django.contrib.auth.models import User
|
||||
from auditlog.registry import auditlog
|
||||
from phonenumber_field.modelfields import PhoneNumberField
|
||||
# from django.contrib.postgres.fields import JSONField
|
||||
|
||||
# import logging
|
||||
|
||||
from django.contrib.postgres.fields import JSONField
|
||||
from uuid import uuid4
|
||||
import logging
|
||||
|
||||
VERBOSE_NAME = _('Webapp')
|
||||
EMAIL_REGEX = r"(^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$)"
|
||||
|
||||
|
||||
class Tag(models.Model):
|
||||
"""Model for tag."""
|
||||
|
||||
slug = models.SlugField(unique=True)
|
||||
name = models.CharField(max_length=127)
|
||||
icon = models.ImageField()
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Tag')
|
||||
verbose_name_plural = _('Tags')
|
||||
|
||||
slug = models.SlugField(unique=True)
|
||||
name = models.CharField(max_length=127)
|
||||
icon = models.ImageField()
|
||||
|
||||
def __str__(self):
|
||||
return _('Tag: {}').format(self.slug)
|
||||
|
||||
@@ -40,83 +42,129 @@ class BaseFeed(models.Model):
|
||||
title = models.CharField(max_length=255)
|
||||
description = models.CharField(max_length=255)
|
||||
content = models.TextField()
|
||||
image = models.ImageField(blank=True, null=True)
|
||||
|
||||
|
||||
class Feed(BaseFeed):
|
||||
"""Model representing feed."""
|
||||
|
||||
publish_time = models.DateTimeField(default=timezone.now)
|
||||
autohide = models.DateTimeField(default=month_from_now)
|
||||
autohide_enabled = models.BooleanField(default=False)
|
||||
|
||||
def __str__(self):
|
||||
return _('Feed: {}').format(self.title)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Feed')
|
||||
verbose_name_plural = _('Feeds')
|
||||
|
||||
|
||||
class Event(BaseFeed):
|
||||
"""Model for event."""
|
||||
|
||||
start_time = models.DateTimeField(default=timezone.now)
|
||||
end_time = models.DateTimeField(default=timezone.now)
|
||||
signupForm = models.ManyToManyField(
|
||||
'SignupForm', blank=True)
|
||||
location = models.CharField(max_length=255, blank=True)
|
||||
publish_time = models.DateTimeField(default=timezone.now)
|
||||
autohide = models.DateTimeField(default=month_from_now)
|
||||
autohide_enabled = models.BooleanField(default=False)
|
||||
deleted = models.BooleanField(default=False)
|
||||
|
||||
def __str__(self):
|
||||
return _('Event: {}').format(self.title)
|
||||
delete_str = _("Deleted: ") if self.deleted else ""
|
||||
return _('{}Feed: {}').format(delete_str, self.title)
|
||||
|
||||
|
||||
class Event(BaseFeed):
|
||||
"""Model for event in guild calendar"""
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Event')
|
||||
verbose_name_plural = _('Events')
|
||||
|
||||
|
||||
class TemplateQuestion(models.Model):
|
||||
"""Stores template questions for signup forms as JSONB"""
|
||||
# question = JSONField()
|
||||
name = models.CharField(max_length=255)
|
||||
question = models.CharField(max_length=255)
|
||||
start_time = models.DateTimeField(default=timezone.now)
|
||||
end_time = models.DateTimeField(default=timezone.now)
|
||||
signupForm = models.ManyToManyField(
|
||||
'SignupForm', blank=True, related_name="event")
|
||||
location = models.CharField(max_length=255, blank=True)
|
||||
deleted = models.BooleanField(default=False)
|
||||
|
||||
def __str__(self):
|
||||
return _('Template questions: {}').format(self.name)
|
||||
delete_str = _("Deleted: ") if self.deleted else ""
|
||||
return _('{}Event: {}').format(delete_str, self.title)
|
||||
|
||||
|
||||
class TemplateQuestion(models.Model):
|
||||
"""
|
||||
NOT IMPLEMENTED!!!
|
||||
Stores template questions for signup forms as JSON format. Used in signup form creation
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Template question')
|
||||
verbose_name_plural = _('Template questions')
|
||||
|
||||
|
||||
class SignupForm(models.Model):
|
||||
"""Model for event signup form. Stores questions in JSONB."""
|
||||
|
||||
title = models.CharField(max_length=255)
|
||||
start_time = models.DateTimeField(default=timezone.now)
|
||||
end_time = models.DateTimeField(default=timezone.now)
|
||||
# question = JSONField()
|
||||
questions = models.TextField(default="[]")
|
||||
visible = models.BooleanField(default=True)
|
||||
name = models.CharField(max_length=255)
|
||||
question = JSONField()
|
||||
|
||||
def __str__(self):
|
||||
return _('#{} {}').format(self.id, self.title)
|
||||
return _('Template questions: {}').format(self.name)
|
||||
|
||||
|
||||
class SignupForm(models.Model):
|
||||
"""Model for event signup form. Stores questions in JSON format."""
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Signup form')
|
||||
verbose_name_plural = _('Signup forms')
|
||||
|
||||
|
||||
class Signup(models.Model):
|
||||
signupForm = models.ForeignKey('SignupForm', on_delete=models.CASCADE)
|
||||
time = models.DateTimeField(default=timezone.now)
|
||||
answer = models.CharField(max_length=255)
|
||||
title = models.CharField(max_length=255)
|
||||
start_time = models.DateTimeField(default=timezone.now)
|
||||
end_time = models.DateTimeField(default=timezone.now)
|
||||
questions = JSONField()
|
||||
schema = JSONField()
|
||||
visible = models.BooleanField(default=True)
|
||||
quota = models.PositiveIntegerField(blank=True, null=True)
|
||||
email_content = models.TextField(blank=True)
|
||||
deleted = models.BooleanField(default=False)
|
||||
|
||||
def __str__(self):
|
||||
return _('Sign-ups: {}').format(self.signupForm)
|
||||
delete_str = _("Deleted: ") if self.deleted else ""
|
||||
return _('#{} {}{}').format(self.id, delete_str, self.title)
|
||||
|
||||
@property
|
||||
def signups(self):
|
||||
return Signup.objects.filter(signupForm=self, deleted=False).order_by('pk')
|
||||
|
||||
@property
|
||||
def isOpen(self):
|
||||
now = timezone.now()
|
||||
return self.start_time <= now and now < self.end_time
|
||||
|
||||
|
||||
class Signup(models.Model):
|
||||
"""
|
||||
Actual signup into any SignupForm. Deletes are soft.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
verbose_name = _('Sign-up')
|
||||
verbose_name_plural = _('Sign-ups')
|
||||
signupForm = models.ForeignKey('SignupForm', on_delete=models.CASCADE)
|
||||
time = models.DateTimeField(default=timezone.now)
|
||||
answer = JSONField()
|
||||
# Answer we use in signupForm signups field. Frontend uses first questions answer as this value.
|
||||
list_name = models.CharField(_('Name'), max_length=255)
|
||||
# If there is email in questions, we save it as own field
|
||||
email = models.EmailField(blank=True, null=True)
|
||||
# Random unique identifier. Used for signup editing by the user.
|
||||
uuid = models.UUIDField(default=uuid4, editable=False)
|
||||
deleted = models.BooleanField(default=False)
|
||||
|
||||
def __str__(self):
|
||||
delete_str = _("Deleted: ") if self.deleted else ""
|
||||
return f"{self.signupForm}: {delete_str}{self.list_name} ({self.pk})"
|
||||
|
||||
|
||||
@receiver(post_save, sender=Signup)
|
||||
def email_on_signup(sender, instance, created, **kwargs):
|
||||
if created and instance.email:
|
||||
# TODO: Possible bug due to many-to-many relationship with events and forms.
|
||||
# TODO: Subject field crashes with lazy loaded translations.
|
||||
try:
|
||||
# subject = _(f"Olet ilmoittautunut tapahtumaan {instance.signupForm.event.first().title}")
|
||||
subject = f"Olet ilmoittautunut tapahtumaan {instance.signupForm.event.first().title}"
|
||||
except AttributeError:
|
||||
# subject = _(f"Olet ilmoittautunut ilmoon {instance.signupForm.title}")
|
||||
subject = f"Olet ilmoittautunut ilmoon {instance.signupForm.title}"
|
||||
send_signup_email(instance.email, subject, instance.id, instance.uuid, instance.signupForm.email_content)
|
||||
|
||||
|
||||
class BaseRole(models.Model):
|
||||
@@ -130,73 +178,30 @@ class BaseRole(models.Model):
|
||||
return '{} ({})'.format(n, _('board member')) if self.is_board else n
|
||||
|
||||
|
||||
class PresetRole(BaseRole):
|
||||
"""Model representing a preset occupation in the guild."""
|
||||
|
||||
description = models.TextField(_('Description'))
|
||||
|
||||
|
||||
class Committee(models.Model):
|
||||
"""
|
||||
Committee model
|
||||
Has many Roles found under variable roles
|
||||
"""
|
||||
class JobAd(models.Model):
|
||||
"""Job advertisements shown on Corporate relations page"""
|
||||
|
||||
class Meta:
|
||||
"""Meta class for Committee class."""
|
||||
verbose_name = _('JobAd')
|
||||
verbose_name_plural = _('JobAds')
|
||||
|
||||
verbose_name = _('Committee')
|
||||
verbose_name_plural = _('Committees')
|
||||
title = models.CharField(max_length=255)
|
||||
description = models.CharField(max_length=255)
|
||||
content = models.TextField()
|
||||
visible = models.BooleanField(default=True)
|
||||
created_at = models.DateTimeField(default=timezone.now)
|
||||
autohide_at = models.DateTimeField(default=month_from_now)
|
||||
autohide_enabled = models.BooleanField(default=False)
|
||||
deleted = models.BooleanField(default=False)
|
||||
|
||||
def __str__(self):
|
||||
return _('Committee: {}').format(self.name)
|
||||
|
||||
name = models.CharField(_("Name"), max_length=255)
|
||||
|
||||
@property
|
||||
def current_roles(self):
|
||||
return self.roles.all().filter(end_date__gte=timezone.now()).filter(start_date__lte=timezone.now())
|
||||
|
||||
|
||||
class Role(PresetRole):
|
||||
"""
|
||||
Model for Role.
|
||||
|
||||
Model representing an active or historical occupation
|
||||
in an official's history.
|
||||
"""
|
||||
|
||||
class Meta:
|
||||
"""Meta class for Role model."""
|
||||
|
||||
verbose_name = _('Role')
|
||||
verbose_name_plural = _('Roles')
|
||||
|
||||
start_date = models.DateField(_('Start date'))
|
||||
end_date = models.DateField(_('End date'))
|
||||
committee = models.ForeignKey('Committee', related_name='roles', on_delete=models.SET_NULL, null=True)
|
||||
|
||||
|
||||
class Official(User):
|
||||
"""Model representing a guild official."""
|
||||
|
||||
class Meta:
|
||||
"""Meta class for Official class."""
|
||||
|
||||
verbose_name = _('Official')
|
||||
verbose_name_plural = _('Officials')
|
||||
|
||||
phone_number = PhoneNumberField(_('Phone number'))
|
||||
role = models.ManyToManyField('Role', related_name='official')
|
||||
|
||||
def __str__(self):
|
||||
return '{} {}'.format(self.first_name, self.last_name)
|
||||
delete_str = _("Deleted: ") if self.deleted else ""
|
||||
return f'{delete_str}{self.title}'
|
||||
|
||||
|
||||
auditlog.register(Tag)
|
||||
auditlog.register(Feed)
|
||||
auditlog.register(Event)
|
||||
auditlog.register(SignupForm)
|
||||
auditlog.register(Signup)
|
||||
auditlog.register(PresetRole)
|
||||
auditlog.register(Role)
|
||||
auditlog.register(Official)
|
||||
auditlog.register(JobAd)
|
||||
|
||||
@@ -2,34 +2,88 @@ from rest_framework import serializers
|
||||
from webapp.models import *
|
||||
|
||||
|
||||
class SignupFormSerializer(serializers.HyperlinkedModelSerializer):
|
||||
class Meta:
|
||||
model = SignupForm
|
||||
fields = ('id', 'title', 'start_time', 'end_time', 'questions')
|
||||
|
||||
|
||||
class EventSerializer(serializers.HyperlinkedModelSerializer):
|
||||
signupForm = SignupFormSerializer(many=True, read_only=True, required=False)
|
||||
signup_id = serializers.PrimaryKeyRelatedField(
|
||||
many=True,
|
||||
class SignupSerializer(serializers.ModelSerializer):
|
||||
signupForm_id = serializers.PrimaryKeyRelatedField(
|
||||
source="signupForm",
|
||||
queryset=SignupForm.objects.all()
|
||||
)
|
||||
tag_id = serializers.PrimaryKeyRelatedField(
|
||||
list_name = serializers.CharField(read_only=True)
|
||||
|
||||
def add_extra_fields(self, validated_data):
|
||||
questions = validated_data["signupForm"].questions
|
||||
name_ids = list(filter(lambda x: x["type"] == "name", questions))
|
||||
email_ids = list(filter(lambda x: x["type"] == "email", questions))
|
||||
|
||||
# Send email to first email field in the form
|
||||
if (len(email_ids) > 0):
|
||||
id = email_ids[0]["id"]
|
||||
email_value = validated_data["answer"].get(id)
|
||||
validated_data["email"] = email_value
|
||||
# Combine all name fields to list_name
|
||||
if (len(name_ids) > 0):
|
||||
# name_value = validated_data["answer"].get(name_fields[0]["id"], None)
|
||||
all_names = map(lambda x: validated_data["answer"].get(x["id"]), name_ids)
|
||||
validated_data["list_name"] = " ".join(all_names)
|
||||
|
||||
def create(self, validated_data):
|
||||
self.add_extra_fields(validated_data)
|
||||
return super().create(validated_data)
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
self.add_extra_fields(validated_data)
|
||||
return super().update(instance, validated_data)
|
||||
|
||||
class Meta:
|
||||
model = Signup
|
||||
fields = ('id', 'signupForm_id', 'answer', 'list_name')
|
||||
extra_kwargs = {
|
||||
'url': {
|
||||
'view_name': 'signup-detail',
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SignupFormSerializer(serializers.ModelSerializer):
|
||||
signups = serializers.SlugRelatedField(
|
||||
slug_field="list_name",
|
||||
many=True,
|
||||
source="tags",
|
||||
queryset=Tag.objects.all()
|
||||
read_only=True,
|
||||
required=False,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = SignupForm
|
||||
fields = ('id', 'title_fi', 'title_en', 'visible', 'isOpen', 'start_time', 'end_time', 'email_content', 'questions', 'schema', 'signups', 'quota')
|
||||
|
||||
|
||||
class EventSerializer(serializers.ModelSerializer):
|
||||
signupForm = SignupFormSerializer(
|
||||
source='filtered_signup_forms',
|
||||
many=True,
|
||||
read_only=True,
|
||||
)
|
||||
|
||||
signup_id = serializers.PrimaryKeyRelatedField(
|
||||
queryset=SignupForm.objects.all(),
|
||||
many=True,
|
||||
write_only=True,
|
||||
)
|
||||
tag_id = serializers.PrimaryKeyRelatedField(
|
||||
queryset=Tag.objects.all(),
|
||||
many=True,
|
||||
write_only=True,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Event
|
||||
fields = ('id', 'tag_id', 'tags', 'visible', 'title', 'description',
|
||||
'content', 'start_time', 'end_time', 'location', 'signup_id', 'signupForm')
|
||||
fields = ('id', 'tag_id', 'tags', 'visible', 'image', 'title_fi', 'title_en', 'description_fi', 'description_en',
|
||||
'content_fi', 'content_en', 'start_time', 'end_time', 'location_fi', 'location_en', 'signup_id', 'signupForm')
|
||||
read_only_fields = ['tags', 'signupForm']
|
||||
depth = 1
|
||||
|
||||
def create(self, validated_data):
|
||||
signupForms = validated_data.pop('signupForm')
|
||||
tags = validated_data.pop('tags')
|
||||
signupForms = validated_data.pop('signup_id', [])
|
||||
tags = validated_data.pop('tag_id')
|
||||
event = Event.objects.create(**validated_data)
|
||||
for form in signupForms:
|
||||
event.signupForm.add(form)
|
||||
@@ -39,27 +93,21 @@ class EventSerializer(serializers.HyperlinkedModelSerializer):
|
||||
return event
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
signupForms = validated_data.pop('signupForm')
|
||||
instance = super(EventSerializer, self).update(instance, validated_data)
|
||||
signupForms = validated_data.pop('signup_id', [])
|
||||
tags = validated_data.pop('tag_id')
|
||||
instance.signupForm.clear()
|
||||
for form_data in signupForms:
|
||||
# form_qs = SignupForms.objects.filter(id=form['id'])
|
||||
instance.signupForm.add(form_data)
|
||||
instance.tags.clear()
|
||||
for form in signupForms:
|
||||
instance.signupForm.add(form)
|
||||
for tag in tags:
|
||||
instance.tags.add(tag)
|
||||
instance = super(EventSerializer, self).update(instance, validated_data)
|
||||
return instance
|
||||
|
||||
|
||||
class SignupSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Signup
|
||||
fields = ('id', 'signupForm', 'answer')
|
||||
extra_kwargs = {
|
||||
'url': {
|
||||
'view_name': 'signup-detail',
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class SavedQuestionsSerializer(serializers.ModelSerializer):
|
||||
question = serializers.JSONField()
|
||||
|
||||
class Meta:
|
||||
model = TemplateQuestion
|
||||
fields = ('id', 'name', 'question')
|
||||
@@ -68,7 +116,7 @@ class SavedQuestionsSerializer(serializers.ModelSerializer):
|
||||
class TagSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Tag
|
||||
fields = ('id', 'slug', 'name', 'icon')
|
||||
fields = ('id', 'slug', 'name_fi', 'name_en', 'icon')
|
||||
|
||||
|
||||
class FeedSerializer(serializers.ModelSerializer):
|
||||
@@ -80,8 +128,8 @@ class FeedSerializer(serializers.ModelSerializer):
|
||||
|
||||
class Meta:
|
||||
model = Feed
|
||||
fields = ('id', 'tags', 'tag_id', 'visible', 'title', 'description',
|
||||
'content', 'publish_time', 'autohide', 'autohide_enabled')
|
||||
fields = ('id', 'tags', 'tag_id', 'visible', 'image', 'title_fi', 'title_en', 'description_fi', 'description_en',
|
||||
'content_fi', 'content_en', 'publish_time', 'autohide', 'autohide_enabled')
|
||||
depth = 1
|
||||
|
||||
def create(self, validated_data):
|
||||
@@ -93,8 +141,7 @@ class FeedSerializer(serializers.ModelSerializer):
|
||||
return feed
|
||||
|
||||
|
||||
class ContactsSerializer(serializers.ModelSerializer):
|
||||
class JobAdSerializer(serializers.ModelSerializer):
|
||||
class Meta:
|
||||
model = Official
|
||||
fields = ('id', 'first_name', 'last_name', 'phone_number', 'role')
|
||||
depth = 2
|
||||
model = JobAd
|
||||
fields = ('id', 'title_fi', 'title_en', 'description_fi', 'description_en', 'content_fi', 'content_en', 'visible', 'autohide_at', 'autohide_enabled')
|
||||
|
||||