Compare commits
66 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a27d06b0d0 | |||
| 7554c1e7e8 | |||
| 50fd4ff9f7 | |||
| ff8230d9c0 | |||
| 3f73fbec62 | |||
| 916e0bdaf0 | |||
| 9e4a7c8569 | |||
| b5839da135 | |||
| f562912492 | |||
| f0a5b6e8e7 | |||
| 8fc3ee534d | |||
| 9b4fa56add | |||
| 90ca91970d | |||
| 955072370f | |||
| 709275c4d3 | |||
| 6f61c9dc32 | |||
| f5432a1ff9 | |||
| f23ce6b39e | |||
| 3a8c455031 | |||
| a6a973f008 | |||
| 01f7911352 | |||
| 55507f89d1 | |||
| 4e0a93631d | |||
| be9e308587 | |||
| 8550a9a02b | |||
| 703bb91bfd | |||
| 6b4a00ebd8 | |||
| 677c1400fa | |||
| a2e08d0ea6 | |||
| 901f2bed96 | |||
| 6004156b6f | |||
| e00323bffe | |||
| 6ef0dbf91b | |||
| 63a4781574 | |||
| e735ebe64a | |||
| f9db8476a1 | |||
| 2a24544056 | |||
| fb7bee5480 | |||
| 8355d10635 | |||
| 21892e277e | |||
| 81e1f994eb | |||
| fc6e02b71b | |||
| 8815ccf667 | |||
| b694370572 | |||
| fda9acfb2f | |||
| 30c6e4809b | |||
| 39754a5e63 | |||
| 0be3ee69be | |||
| c6f0f4615b | |||
| 3ac5400b79 | |||
| 429d3a0602 | |||
| 1b086843dc | |||
| b9280ea026 | |||
| b36022e546 | |||
| 9bb57840a7 | |||
| 36bd74c6cc | |||
| a2615ae27d | |||
| f7de9e32d3 | |||
| 57d8c4321f | |||
| 632eedea9c | |||
| 1405d89d9a | |||
| da1ae8d721 | |||
| 52a83b9336 | |||
| c1a1f6e534 | |||
| f79d1467f7 | |||
| 40cf9121b6 |
@@ -1,9 +1,5 @@
|
||||
[report]
|
||||
show_missing = True
|
||||
omit =
|
||||
*/migrations/*
|
||||
*/admin.py
|
||||
*/translation.py
|
||||
[run]
|
||||
omit =
|
||||
*/migrations/*
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
DEPLOY_ENV=local
|
||||
SENTRY_DSN=
|
||||
HOST=api.dev.sahkoinsinoorikilta.fi
|
||||
HOST=localhost
|
||||
DEBUG=True
|
||||
SECRET_KEY=7p$85^4ibb^p4-=vs44b7!y0e-zemugze18@a#30&71=a8)dp(
|
||||
DB_NAME=postgres
|
||||
DB_USER=postgres
|
||||
DB_PASSWD=postgres
|
||||
DB_HOST=db
|
||||
DB_HOST=localhost
|
||||
DB_PORT=5432
|
||||
EMAIL_API_KEY=
|
||||
GROUP_KEY=
|
||||
GOOGLE_CREDS='{}'
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
members/static/js/lib
|
||||
infoscreen/static/js/lib
|
||||
webapp/static/js/lib
|
||||
static/js/lib
|
||||
collected_static
|
||||
venv
|
||||
-251
@@ -1,251 +0,0 @@
|
||||
{
|
||||
"env": {
|
||||
"browser": true,
|
||||
"jquery": true
|
||||
},
|
||||
"globals": {
|
||||
"angular": true,
|
||||
"noty": true,
|
||||
"_": true,
|
||||
"moment": true
|
||||
},
|
||||
"extends": "eslint:recommended",
|
||||
"rules": {
|
||||
"no-unused-vars": "warn",
|
||||
"accessor-pairs": "error",
|
||||
"array-bracket-spacing": "off",
|
||||
"array-callback-return": "error",
|
||||
"arrow-body-style": "error",
|
||||
"arrow-parens": "error",
|
||||
"arrow-spacing": "error",
|
||||
"block-scoped-var": "off",
|
||||
"block-spacing": "off",
|
||||
"brace-style": "off",
|
||||
"callback-return": "off",
|
||||
"camelcase": "off",
|
||||
"capitalized-comments": "off",
|
||||
"class-methods-use-this": "error",
|
||||
"comma-dangle": "off",
|
||||
"comma-spacing": "off",
|
||||
"comma-style": "off",
|
||||
"complexity": "off",
|
||||
"computed-property-spacing": "off",
|
||||
"consistent-return": "off",
|
||||
"consistent-this": "off",
|
||||
"curly": "off",
|
||||
"default-case": "off",
|
||||
"dot-location": [
|
||||
"error",
|
||||
"property"
|
||||
],
|
||||
"dot-notation": "off",
|
||||
"eol-last": "off",
|
||||
"eqeqeq": "off",
|
||||
"func-call-spacing": "error",
|
||||
"func-name-matching": "error",
|
||||
"func-names": "off",
|
||||
"func-style": "off",
|
||||
"generator-star-spacing": "error",
|
||||
"global-require": "off",
|
||||
"guard-for-in": "off",
|
||||
"handle-callback-err": "off",
|
||||
"id-blacklist": "error",
|
||||
"id-length": "off",
|
||||
"id-match": "error",
|
||||
"indent": "off",
|
||||
"init-declarations": "off",
|
||||
"jsx-quotes": "error",
|
||||
"key-spacing": "off",
|
||||
"keyword-spacing": "off",
|
||||
"line-comment-position": "off",
|
||||
"linebreak-style": "off",
|
||||
"lines-around-comment": "off",
|
||||
"lines-around-directive": "off",
|
||||
"max-depth": "off",
|
||||
"max-len": "off",
|
||||
"max-lines": "off",
|
||||
"max-nested-callbacks": "error",
|
||||
"max-params": "off",
|
||||
"max-statements": "off",
|
||||
"max-statements-per-line": "off",
|
||||
"multiline-ternary": "off",
|
||||
"new-parens": "off",
|
||||
"newline-after-var": "off",
|
||||
"newline-before-return": "off",
|
||||
"newline-per-chained-call": "off",
|
||||
"no-alert": "error",
|
||||
"no-array-constructor": "off",
|
||||
"no-await-in-loop": "error",
|
||||
"no-bitwise": "off",
|
||||
"no-caller": "error",
|
||||
"no-catch-shadow": "off",
|
||||
"no-confusing-arrow": "error",
|
||||
"no-constant-condition": [
|
||||
"error",
|
||||
{
|
||||
"checkLoops": false
|
||||
}
|
||||
],
|
||||
"no-continue": "off",
|
||||
"no-div-regex": "error",
|
||||
"no-duplicate-imports": "error",
|
||||
"no-else-return": "off",
|
||||
"no-empty-function": "off",
|
||||
"no-eq-null": "off",
|
||||
"no-eval": "error",
|
||||
"no-extend-native": "error",
|
||||
"no-extra-bind": "error",
|
||||
"no-extra-label": "error",
|
||||
"no-extra-parens": "off",
|
||||
"no-floating-decimal": "off",
|
||||
"no-implicit-coercion": [
|
||||
"error",
|
||||
{
|
||||
"boolean": false,
|
||||
"number": false,
|
||||
"string": false
|
||||
}
|
||||
],
|
||||
"no-implicit-globals": "off",
|
||||
"no-implied-eval": "error",
|
||||
"no-inline-comments": "off",
|
||||
"no-inner-declarations": [
|
||||
"error",
|
||||
"functions"
|
||||
],
|
||||
"no-invalid-this": "off",
|
||||
"no-iterator": "error",
|
||||
"no-label-var": "error",
|
||||
"no-labels": "error",
|
||||
"no-lone-blocks": "error",
|
||||
"no-lonely-if": "off",
|
||||
"no-loop-func": "error",
|
||||
"no-magic-numbers": "off",
|
||||
"no-mixed-operators": "off",
|
||||
"no-mixed-requires": "error",
|
||||
"no-multi-assign": "off",
|
||||
"no-multi-spaces": "off",
|
||||
"no-multi-str": "error",
|
||||
"no-multiple-empty-lines": "off",
|
||||
"no-native-reassign": "off",
|
||||
"no-negated-condition": "off",
|
||||
"no-negated-in-lhs": "error",
|
||||
"no-nested-ternary": "off",
|
||||
"no-new": "error",
|
||||
"no-new-func": "off",
|
||||
"no-new-object": "error",
|
||||
"no-new-require": "error",
|
||||
"no-new-wrappers": "error",
|
||||
"no-octal-escape": "error",
|
||||
"no-param-reassign": "off",
|
||||
"no-path-concat": "error",
|
||||
"no-plusplus": "off",
|
||||
"no-process-env": "error",
|
||||
"no-process-exit": "error",
|
||||
"no-proto": "error",
|
||||
"no-prototype-builtins": "off",
|
||||
"no-restricted-globals": "error",
|
||||
"no-restricted-imports": "error",
|
||||
"no-restricted-modules": "error",
|
||||
"no-restricted-properties": "error",
|
||||
"no-restricted-syntax": "error",
|
||||
"no-return-assign": "off",
|
||||
"no-return-await": "error",
|
||||
"no-script-url": "error",
|
||||
"no-self-compare": "error",
|
||||
"no-sequences": "off",
|
||||
"no-shadow": "off",
|
||||
"no-shadow-restricted-names": "error",
|
||||
"no-spaced-func": "error",
|
||||
"no-sync": "error",
|
||||
"no-tabs": "off",
|
||||
"no-template-curly-in-string": "error",
|
||||
"no-ternary": "off",
|
||||
"no-throw-literal": "off",
|
||||
"no-trailing-spaces": "off",
|
||||
"no-undef-init": "error",
|
||||
"no-undefined": "off",
|
||||
"no-underscore-dangle": "off",
|
||||
"no-unmodified-loop-condition": "error",
|
||||
"no-unneeded-ternary": [
|
||||
"error",
|
||||
{
|
||||
"defaultAssignment": true
|
||||
}
|
||||
],
|
||||
"no-unused-expressions": "off",
|
||||
"no-use-before-define": "off",
|
||||
"no-useless-call": "off",
|
||||
"no-useless-computed-key": "error",
|
||||
"no-useless-concat": "error",
|
||||
"no-useless-constructor": "error",
|
||||
"no-useless-escape": "off",
|
||||
"no-useless-rename": "error",
|
||||
"no-useless-return": "error",
|
||||
"no-var": "off",
|
||||
"no-void": "off",
|
||||
"no-warning-comments": "off",
|
||||
"no-whitespace-before-property": "error",
|
||||
"no-with": "error",
|
||||
"object-curly-newline": "off",
|
||||
"object-curly-spacing": "off",
|
||||
"object-property-newline": "off",
|
||||
"object-shorthand": "off",
|
||||
"one-var": "off",
|
||||
"one-var-declaration-per-line": "off",
|
||||
"operator-assignment": "off",
|
||||
"operator-linebreak": "off",
|
||||
"padded-blocks": "off",
|
||||
"prefer-arrow-callback": "off",
|
||||
"prefer-const": "error",
|
||||
"prefer-destructuring": [
|
||||
"error",
|
||||
{
|
||||
"array": false,
|
||||
"object": false
|
||||
}
|
||||
],
|
||||
"prefer-numeric-literals": "error",
|
||||
"prefer-promise-reject-errors": "error",
|
||||
"prefer-reflect": "off",
|
||||
"prefer-rest-params": "off",
|
||||
"prefer-spread": "off",
|
||||
"prefer-template": "off",
|
||||
"quote-props": "off",
|
||||
"quotes": "off",
|
||||
"radix": "off",
|
||||
"require-await": "error",
|
||||
"require-jsdoc": "off",
|
||||
"rest-spread-spacing": "error",
|
||||
"semi": "off",
|
||||
"semi-spacing": "off",
|
||||
"sort-imports": "error",
|
||||
"sort-keys": "off",
|
||||
"sort-vars": "off",
|
||||
"space-before-blocks": "off",
|
||||
"space-before-function-paren": "off",
|
||||
"space-in-parens": "off",
|
||||
"space-infix-ops": "off",
|
||||
"space-unary-ops": [
|
||||
"error",
|
||||
{
|
||||
"nonwords": false,
|
||||
"words": false
|
||||
}
|
||||
],
|
||||
"spaced-comment": "off",
|
||||
"strict": "off",
|
||||
"symbol-description": "error",
|
||||
"template-curly-spacing": "error",
|
||||
"unicode-bom": [
|
||||
"error",
|
||||
"never"
|
||||
],
|
||||
"valid-jsdoc": "off",
|
||||
"vars-on-top": "off",
|
||||
"wrap-iife": "off",
|
||||
"wrap-regex": "off",
|
||||
"yield-star-spacing": "error",
|
||||
"yoda": "off"
|
||||
}
|
||||
}
|
||||
+170
-112
@@ -1,131 +1,189 @@
|
||||
stages:
|
||||
- setup
|
||||
- audit
|
||||
- lint
|
||||
- test
|
||||
- publish
|
||||
- deploy
|
||||
- setup
|
||||
- audit
|
||||
- lint
|
||||
- test
|
||||
- publish
|
||||
- deploy
|
||||
- cleanup
|
||||
|
||||
install:
|
||||
image: node:16
|
||||
stage: setup
|
||||
script:
|
||||
- npm ci
|
||||
artifacts:
|
||||
paths:
|
||||
- node_modules
|
||||
expire_in: 1 week
|
||||
image: node:22
|
||||
stage: setup
|
||||
only:
|
||||
- pushes
|
||||
script:
|
||||
- npm ci
|
||||
artifacts:
|
||||
paths:
|
||||
- node_modules
|
||||
expire_in: 1 week
|
||||
|
||||
audit:
|
||||
image: python:3.9
|
||||
stage: audit
|
||||
needs: []
|
||||
before_script:
|
||||
- pip install poetry==1.1.13
|
||||
- poetry config virtualenvs.create false
|
||||
- poetry install --no-interaction --no-ansi
|
||||
script:
|
||||
- safety check
|
||||
image: python:3.12.9
|
||||
stage: audit
|
||||
allow_failure: true
|
||||
only:
|
||||
- pushes
|
||||
needs: []
|
||||
before_script:
|
||||
- pip install poetry==2.0.1
|
||||
- poetry config virtualenvs.create false
|
||||
- poetry install --no-interaction --no-ansi
|
||||
script:
|
||||
- safety check
|
||||
|
||||
test:
|
||||
image: python:3.9
|
||||
stage: test
|
||||
needs: []
|
||||
services:
|
||||
- postgres:12
|
||||
variables:
|
||||
POSTGRES_DB: ci
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
DATABASE_URL: "postgresql://postgres:postgres@postgres:5432/$POSTGRES_DB"
|
||||
DB_HOST: postgres
|
||||
before_script:
|
||||
- pip install poetry==1.1.13
|
||||
- poetry config virtualenvs.create false
|
||||
- poetry install --no-interaction --no-ansi
|
||||
script:
|
||||
- python manage.py migrate --noinput
|
||||
- python manage.py createdefaultadmin
|
||||
- python manage.py test
|
||||
image: python:3.12.9
|
||||
stage: test
|
||||
only:
|
||||
- pushes
|
||||
needs: []
|
||||
services:
|
||||
- postgres:12
|
||||
variables:
|
||||
POSTGRES_DB: ci
|
||||
POSTGRES_USER: postgres
|
||||
POSTGRES_PASSWORD: postgres
|
||||
DATABASE_URL: "postgresql://postgres:postgres@postgres:5432/$POSTGRES_DB"
|
||||
DB_HOST: postgres
|
||||
before_script:
|
||||
- pip install poetry==2.0.1
|
||||
- poetry config virtualenvs.create false
|
||||
- poetry install --no-interaction --no-ansi
|
||||
script:
|
||||
- python manage.py migrate --noinput
|
||||
- python manage.py createdefaultadmin
|
||||
- python manage.py test
|
||||
|
||||
lint:py:
|
||||
image: python:3.9
|
||||
stage: lint
|
||||
needs: []
|
||||
script:
|
||||
- pip install black==22.3.0
|
||||
- black --check .
|
||||
image: python:3.12.9
|
||||
stage: lint
|
||||
only:
|
||||
- pushes
|
||||
needs: []
|
||||
script:
|
||||
- pip install black==22.3.0
|
||||
- black --check .
|
||||
|
||||
lint:js:
|
||||
image: node:16
|
||||
stage: lint
|
||||
needs: ["install"]
|
||||
script:
|
||||
- npm run lint:js
|
||||
image: node:22
|
||||
stage: lint
|
||||
only:
|
||||
- pushes
|
||||
needs: ["install"]
|
||||
script:
|
||||
- npm run lint:js
|
||||
|
||||
lint:md:
|
||||
image: node:16
|
||||
stage: lint
|
||||
needs: ["install"]
|
||||
script:
|
||||
- npm run lint:md
|
||||
image: node:22
|
||||
stage: lint
|
||||
only:
|
||||
- pushes
|
||||
needs: ["install"]
|
||||
script:
|
||||
- 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"
|
||||
image: docker:25-cli
|
||||
stage: publish
|
||||
needs: ["test", "lint:py", "lint:js", "lint:md"]
|
||||
services:
|
||||
- docker:25-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:
|
||||
stage: deploy
|
||||
image: docker:stable
|
||||
only:
|
||||
- develop
|
||||
environment:
|
||||
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"
|
||||
image: docker:25-cli
|
||||
stage: deploy
|
||||
only:
|
||||
- develop
|
||||
environment:
|
||||
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_JOB_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: https://api.sahkoinsinoorikilta.fi
|
||||
when: manual
|
||||
variables:
|
||||
DOCKER_HOST: $CI_DOCKER_HOST
|
||||
DOCKER_TLS_VERIFY: 1
|
||||
before_script:
|
||||
- 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:
|
||||
- docker stack deploy --with-registry-auth -c stack-compose.yml "$SERVICE_NAME"
|
||||
after_script:
|
||||
- docker logout "$CI_REGISTRY"
|
||||
stage: deploy
|
||||
image: docker:25-cli
|
||||
only:
|
||||
- master
|
||||
environment:
|
||||
name: production
|
||||
url: https://api.sahkoinsinoorikilta.fi
|
||||
when: manual
|
||||
variables:
|
||||
DOCKER_HOST: $CI_DOCKER_HOST
|
||||
DOCKER_TLS_VERIFY: 1
|
||||
before_script:
|
||||
- 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_JOB_TOKEN $CI_REGISTRY
|
||||
script:
|
||||
- docker stack deploy --with-registry-auth -c stack-compose.yml "$SERVICE_NAME"
|
||||
after_script:
|
||||
- docker logout "$CI_REGISTRY"
|
||||
|
||||
docker_prune:dev:
|
||||
image: docker:stable
|
||||
stage: cleanup
|
||||
only:
|
||||
- schedules
|
||||
environment:
|
||||
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_JOB_TOKEN $CI_REGISTRY
|
||||
script:
|
||||
- docker system prune
|
||||
after_script:
|
||||
- docker logout "$CI_REGISTRY"
|
||||
|
||||
docker_prune:prod:
|
||||
image: docker:stable
|
||||
stage: cleanup
|
||||
only:
|
||||
- schedules
|
||||
environment:
|
||||
name: production
|
||||
url: https://api.sahkoinsinoorikilta.fi
|
||||
variables:
|
||||
DOCKER_HOST: $CI_DOCKER_HOST
|
||||
DOCKER_TLS_VERIFY: 1
|
||||
before_script:
|
||||
- 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_JOB_TOKEN $CI_REGISTRY
|
||||
script:
|
||||
- docker system prune
|
||||
after_script:
|
||||
- docker logout "$CI_REGISTRY"
|
||||
|
||||
@@ -1 +0,0 @@
|
||||
_
|
||||
Executable → Regular
-3
@@ -1,6 +1,3 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
PURPLE='\033[0;35m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
#!/bin/sh
|
||||
. "$(dirname "$0")/_/husky.sh"
|
||||
|
||||
PURPLE='\033[0;35m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
|
||||
+1
-1
@@ -1 +1 @@
|
||||
3.9
|
||||
3.12.9
|
||||
|
||||
+4
-3
@@ -1,13 +1,14 @@
|
||||
FROM python:3.9-slim-buster as builder
|
||||
FROM python:3.12.9-slim-bullseye AS builder
|
||||
ENV PYTHONUNBUFFERED 1
|
||||
COPY . ./
|
||||
|
||||
ENV POETRY_VERSION=1.1.13
|
||||
ENV POETRY_VERSION=2.0.1
|
||||
|
||||
RUN pip install "poetry==$POETRY_VERSION"
|
||||
RUN poetry self add poetry-plugin-export
|
||||
RUN poetry export --without-hashes > requirements.txt
|
||||
|
||||
FROM python:3.9-slim-buster as server
|
||||
FROM python:3.12.9-slim-bullseye AS server
|
||||
|
||||
WORKDIR /app
|
||||
COPY . ./
|
||||
|
||||
@@ -1,24 +1,14 @@
|
||||
# SIKWEB 2.0
|
||||
# Web 2.0 Backend
|
||||
|
||||
A modern web app using a Django backend and an Angular frontend.
|
||||
[Django](https://www.djangoproject.com/) backend containing multiple small applications and api for Next.js frontend.
|
||||
|
||||
## Components
|
||||
* **Web app:** Backend for the main website.
|
||||
* **Member register:** Data table app for viewing and modifying the member register, member applications and membership payments.
|
||||
* **Kaehmy:** Form for creating and listing kaehmys
|
||||
* **Ohlhafv:** Form for creating and listing ohlhafv challenges.
|
||||
* **Infoscreen:** Angular-based slideshow app for the guild room's screens.
|
||||
|
||||
### Infoscreen
|
||||
|
||||
Angular-based slideshow app for the guild room's screens.
|
||||
|
||||
### Member register
|
||||
|
||||
Data table app for viewing and modifying the member register, member applications and membership payments.
|
||||
|
||||
### Web app
|
||||
|
||||
Mostly static website with an event calendar and news feed.
|
||||
|
||||
## Accessing the source
|
||||
|
||||
### Clone this repository and enter it
|
||||
## Installation
|
||||
|
||||
Set up your SSH key authentication in GitLab Profile Settings. Then clone the repository and checkout the development branch:
|
||||
|
||||
@@ -28,30 +18,54 @@ cd web2.0-backend
|
||||
git checkout develop
|
||||
```
|
||||
|
||||
## Development
|
||||
Copy env file for local use:
|
||||
|
||||
```bash
|
||||
cp .env.dev .env
|
||||
```
|
||||
|
||||
### Poetry
|
||||
|
||||
For depedencies and virtual environment, we use [poetry](https://python-poetry.org/).
|
||||
|
||||
First install [python](https://wiki.python.org/moin/BeginnersGuide/Download). Then install poetry:
|
||||
|
||||
```bash
|
||||
python3 -m pip install poetry
|
||||
python -m pip install poetry==2.0.1
|
||||
```
|
||||
|
||||
The easiest integration with VSCode is to have poetry install virtual environment in project folder, configured with CMD
|
||||
|
||||
```bash
|
||||
python3 -m poetry config virtualenvs.in-project true
|
||||
python -m poetry config virtualenvs.in-project true
|
||||
```
|
||||
|
||||
Start developing by install dependencies first
|
||||
### Node
|
||||
|
||||
#### CMDs
|
||||
We use Node.js for few development tasks, like linting. Easiest way to install Node is [nvm](https://github.com/nvm-sh/nvm). After installing install dependencies:
|
||||
|
||||
```bash
|
||||
npm install
|
||||
```
|
||||
|
||||
TODO: List scripts
|
||||
|
||||
### Database
|
||||
|
||||
To run a local development database **[docker](https://docs.docker.com/engine/install/)** is recommended. If you want to additianally use a db management tool **[pgAdmin](https://www.pgadmin.org/download/)** is nice.
|
||||
|
||||
After installing docker use the following to create a database:
|
||||
|
||||
```bash
|
||||
docker run --name sik.web.db -e POSTGRES_PASSWORD=postgres -p 5432:5432 -d postgres:12
|
||||
```
|
||||
|
||||
## Development
|
||||
|
||||
Activate virtual environment in shell
|
||||
|
||||
```bash
|
||||
python3 -m poetry shell
|
||||
eval $(python -m poetry env activate)
|
||||
```
|
||||
|
||||
Install dependencies
|
||||
@@ -60,20 +74,15 @@ Install dependencies
|
||||
poetry install
|
||||
```
|
||||
|
||||
### npm scripts
|
||||
|
||||
We use Node.js for few development tasks, like linting. Easiest way to install Node is [nvm](https://github.com/nvm-sh/nvm).
|
||||
|
||||
TODO: List scripts
|
||||
|
||||
### Initializing data
|
||||
|
||||
Run the following `manage.py` commands. Do not run these in production without thinking!
|
||||
Run the following `manage.py` commands to initialize a new database. Do not run these in production without thinking!
|
||||
|
||||
```bash
|
||||
python manage.py createdefaultadmin # creates an admin user
|
||||
python manage.py initialize # creates user groups
|
||||
python manage.py createdummydata # creates dummy members to the member register
|
||||
python manage.py migrate # run migrations
|
||||
python manage.py createdefaultadmin # creates an admin user
|
||||
python manage.py initialize # creates user groups
|
||||
python manage.py createdummydata # creates dummy members to the member register
|
||||
```
|
||||
|
||||
### Running
|
||||
@@ -82,8 +91,6 @@ python manage.py createdummydata # creates dummy members to the member regis
|
||||
python manage.py runserver
|
||||
```
|
||||
|
||||
#### Visit the page
|
||||
|
||||
Visit [https://localhost:8000](https://localhost:8000) in your browser!
|
||||
|
||||
Using address `0.0.0.0` will bind to all IP addresses. Using `localhost` will only bind to your machine.
|
||||
@@ -99,7 +106,7 @@ When you start working on a feature, create a feature branch for your changes. T
|
||||
Example of creating a feature branch:
|
||||
|
||||
```bash
|
||||
git checkout -b feature-error-page
|
||||
git checkout -b feature-branch-name
|
||||
```
|
||||
|
||||
When your changes are ready and the code works without errors, submit a merge request to `develop` in GitLab. Another developer reviews your changes and runs the merge. Feature branches should be closed on merge.
|
||||
@@ -110,16 +117,18 @@ Merge requests to `master` should be reviewed by multiple developers. Only a mod
|
||||
|
||||
### Linting
|
||||
|
||||
Lint python files using `pycodestyle` with
|
||||
Lint python files using `black` with
|
||||
|
||||
```bash
|
||||
pycodestyle --config=pycodestyle.cfg --count .
|
||||
npm run lint:py # check changes
|
||||
npm run lint:py:fix # fix errors
|
||||
```
|
||||
|
||||
Lint javascript and markdown using `eslint` and `remark` with
|
||||
|
||||
```bash
|
||||
npm test
|
||||
npm run lint:md # markdown
|
||||
npm run lint:js # javascript
|
||||
```
|
||||
|
||||
Use an editor with linting capabilities to write pretty code that passes linting. Examples include _VSCode_, _Atom_ and _Pycharm_.
|
||||
@@ -140,6 +149,8 @@ Tests are located in `tests.py` under every subproject.
|
||||
|
||||
Project is run in production with Docker. See `Dockerfile` for details.
|
||||
|
||||
For more information about deployment check **[infra](https://gitlab.com/sahkoinsinoorikilta/vtmk/infra)** repository.
|
||||
|
||||
## GitLab CI
|
||||
|
||||
All pushed changes go through the GitLab Continuous Integration, which consists of automated unit testing and linting. Make sure your changes pass both before merging to `develop` or `master`.
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
version: '3'
|
||||
|
||||
services:
|
||||
db:
|
||||
image: postgres:12
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
import globals from "globals";
|
||||
import js from "@eslint/js";
|
||||
|
||||
|
||||
export default [
|
||||
{
|
||||
ignores: ["**/.venv/", "**/collected_static/", "**/static/js/lib/**"],
|
||||
},
|
||||
{
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
...globals.jquery,
|
||||
angular: true,
|
||||
moment: true,
|
||||
_: true
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
...js.configs.recommended
|
||||
}
|
||||
];
|
||||
@@ -7,7 +7,7 @@ from django import forms
|
||||
from django.utils import timezone
|
||||
from django.contrib.contenttypes.fields import GenericForeignKey
|
||||
from django.contrib.contenttypes.models import ContentType
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
|
||||
class InfoItem(models.Model):
|
||||
|
||||
+23
-23
@@ -1,6 +1,6 @@
|
||||
"""File containing infoscreen urls."""
|
||||
|
||||
from django.conf.urls import url
|
||||
from django.urls import re_path
|
||||
from django.conf import settings
|
||||
|
||||
from infoscreen.views import index
|
||||
@@ -27,28 +27,28 @@ from infoscreen.views import createApyItem
|
||||
from infoscreen.views import get_apy_json
|
||||
|
||||
urlpatterns = [
|
||||
url(r"^$", default),
|
||||
url(r"^admin$", admin),
|
||||
url(r"^(?P<idx>\d+)$", index),
|
||||
url(r"^items$", info_items),
|
||||
url(r"^rotation/(?P<idx>\d+)$", rotation),
|
||||
url(r"^rotations$", rotations),
|
||||
url(r"^instance$", createInstance),
|
||||
url(r"^instance/(?P<idx>\d+)$", deleteInstance),
|
||||
url(r"^types$", info_types),
|
||||
url(r"^delete_item/(?P<type_id>\d+)/(?P<idx>\d+)$", delete_info_item),
|
||||
url(r"^create_external_image$", createExternalImageInfoItem),
|
||||
url(r"^create_image$", create_image_item),
|
||||
url(r"^create_video$", create_video_item),
|
||||
url(r"^create_abbitem$", createABBItem),
|
||||
url(r"^create_sossoitem$", createSossoItem),
|
||||
url(r"^create_lunchitem$", createLunchItem),
|
||||
url(r"^create_eventitem$", createEventItem),
|
||||
url(r"^create_apyitem$", createApyItem),
|
||||
url(r"^create_websiteitem$", createExternalWebsiteItem),
|
||||
url(r"^create_rotation$", create_rotation),
|
||||
url(r"^delete_rotation/(?P<id>\d+)$", delete_rotation),
|
||||
url(r"^apyjson", get_apy_json),
|
||||
re_path(r"^$", default),
|
||||
re_path(r"^admin$", admin),
|
||||
re_path(r"^(?P<idx>\d+)$", index),
|
||||
re_path(r"^items$", info_items),
|
||||
re_path(r"^rotation/(?P<idx>\d+)$", rotation),
|
||||
re_path(r"^rotations$", rotations),
|
||||
re_path(r"^instance$", createInstance),
|
||||
re_path(r"^instance/(?P<idx>\d+)$", deleteInstance),
|
||||
re_path(r"^types$", info_types),
|
||||
re_path(r"^delete_item/(?P<type_id>\d+)/(?P<idx>\d+)$", delete_info_item),
|
||||
re_path(r"^create_external_image$", createExternalImageInfoItem),
|
||||
re_path(r"^create_image$", create_image_item),
|
||||
re_path(r"^create_video$", create_video_item),
|
||||
re_path(r"^create_abbitem$", createABBItem),
|
||||
re_path(r"^create_sossoitem$", createSossoItem),
|
||||
re_path(r"^create_lunchitem$", createLunchItem),
|
||||
re_path(r"^create_eventitem$", createEventItem),
|
||||
re_path(r"^create_apyitem$", createApyItem),
|
||||
re_path(r"^create_websiteitem$", createExternalWebsiteItem),
|
||||
re_path(r"^create_rotation$", create_rotation),
|
||||
re_path(r"^delete_rotation/(?P<id>\d+)$", delete_rotation),
|
||||
re_path(r"^apyjson", get_apy_json),
|
||||
]
|
||||
|
||||
if settings.DEBUG:
|
||||
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
from kaehmy.models import PresetRole, CustomRole, Application, Comment, BaseRole
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
VERBOSE_NAME = _("Kaehmy")
|
||||
|
||||
@@ -17,7 +17,7 @@ class BaseRole(models.Model):
|
||||
("corporate", _("Corporate affairs")),
|
||||
("freshman", _("Freshmen")),
|
||||
("international", _("International")),
|
||||
("external", _("External affairs")),
|
||||
("siwa", _("SIK's free time")),
|
||||
("media", _("Media")),
|
||||
("tech", _("Technology")),
|
||||
("wellbeing", _("Wellbeing")),
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
import django_tables2 as tables
|
||||
from django.db.models import Count, Q
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from kaehmy.models import Application
|
||||
|
||||
|
||||
+8
-8
@@ -1,8 +1,8 @@
|
||||
"""Kaehmy urls."""
|
||||
|
||||
from django.conf.urls import url
|
||||
from django.urls import re_path
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from kaehmy.views import view
|
||||
from kaehmy.views import list_view
|
||||
@@ -13,12 +13,12 @@ from kaehmy.views import export_view
|
||||
|
||||
urlpatterns = [
|
||||
# kaehmy
|
||||
url(r"^new", view),
|
||||
url(r"^submit", submit),
|
||||
url(r"^add_comment", comment),
|
||||
url(r"^statistics", statistics_view),
|
||||
url(r"^export", export_view),
|
||||
url(r"^$", list_view),
|
||||
re_path(r"^new", view),
|
||||
re_path(r"^submit", submit),
|
||||
re_path(r"^add_comment", comment),
|
||||
re_path(r"^statistics", statistics_view),
|
||||
re_path(r"^export", export_view),
|
||||
re_path(r"^$", list_view),
|
||||
]
|
||||
|
||||
if settings.DEBUG:
|
||||
|
||||
@@ -123,6 +123,7 @@ def submit(request, *args, **kwargs):
|
||||
application = form.save()
|
||||
custom_name = form.cleaned_data.get("custom_role_name")
|
||||
custom_is_board = form.cleaned_data.get("custom_role_is_board")
|
||||
kaehmybot_allowed = form.cleaned_data.get("kaehmybot") == "1"
|
||||
|
||||
if len(custom_name) > 0:
|
||||
custom_role = CustomRole(name=custom_name, is_board=custom_is_board)
|
||||
|
||||
Binary file not shown.
@@ -104,8 +104,8 @@ msgid "International"
|
||||
msgstr "International"
|
||||
|
||||
#: kaehmy/models.py:20
|
||||
msgid "External affairs"
|
||||
msgstr "External affairs"
|
||||
msgid "SIK's free time"
|
||||
msgstr "SIK's free time"
|
||||
|
||||
#: kaehmy/models.py:21
|
||||
msgid "Media"
|
||||
@@ -637,7 +637,8 @@ msgstr ""
|
||||
"This list contains both board and non-board positions, categorized by area "
|
||||
"of responsibility.\n"
|
||||
"If you have anything to ask about the positions, seek out people who have "
|
||||
"held that position before or contact the board.\n"
|
||||
"held that position before or consult <a href=\"https://static.sahkoinsinoorikilta.fi/uus_webi/"
|
||||
"kahmyguide.pdf\">kähmy guide</a>.\n"
|
||||
"Best positions to consider for English speaking people are in the "
|
||||
"International category."
|
||||
|
||||
|
||||
Binary file not shown.
@@ -105,8 +105,8 @@ msgid "International"
|
||||
msgstr "International"
|
||||
|
||||
#: kaehmy/models.py:20
|
||||
msgid "External affairs"
|
||||
msgstr "Ulkosuhteet"
|
||||
msgid "SIK's free time"
|
||||
msgstr "SIKin Wapaa-aika (SiWa)"
|
||||
|
||||
#: kaehmy/models.py:21
|
||||
msgid "Media"
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
from django import forms
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from members.models import Member, Payment, Request
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
from django.db import models
|
||||
from django.utils import timezone
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.db.models import Q, OuterRef, Subquery
|
||||
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
"""File containing member application django tables."""
|
||||
|
||||
import django_tables2 as tables
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.translation import gettext as _
|
||||
from django.core.exceptions import ObjectDoesNotExist
|
||||
from django.db.models import F, OuterRef, Subquery
|
||||
from django.utils import timezone
|
||||
|
||||
+33
-33
@@ -1,6 +1,6 @@
|
||||
"""File containing Member application URLs."""
|
||||
|
||||
from django.conf.urls import url
|
||||
from django.urls import re_path
|
||||
from django.conf import settings
|
||||
from django.contrib.auth.decorators import login_required, permission_required
|
||||
|
||||
@@ -42,61 +42,61 @@ from members.views import application_submit
|
||||
|
||||
urlpatterns = [
|
||||
# landing page
|
||||
url(r"^$", member_list),
|
||||
url(r"^list$", member_list),
|
||||
re_path(r"^$", member_list),
|
||||
re_path(r"^list$", member_list),
|
||||
# add member form view
|
||||
url(r"^add$", member_add),
|
||||
re_path(r"^add$", member_add),
|
||||
# add many members view
|
||||
url(r"^add_many$", member_add_many),
|
||||
re_path(r"^add_many$", member_add_many),
|
||||
# edit member information view
|
||||
url(r"^edit/(?P<index>\d+)$", member_edit),
|
||||
re_path(r"^edit/(?P<index>\d+)$", member_edit),
|
||||
# delete confirmation view
|
||||
url(r"^delete_member_confirm/(?P<index>\d+)$", member_delete_confirm),
|
||||
re_path(r"^delete_member_confirm/(?P<index>\d+)$", member_delete_confirm),
|
||||
# list all member applications
|
||||
url(r"^applications$", application_list),
|
||||
re_path(r"^applications$", application_list),
|
||||
# edit member application
|
||||
url(r"^edit_application/(?P<index>\d+)$", application_edit),
|
||||
re_path(r"^edit_application/(?P<index>\d+)$", application_edit),
|
||||
# post request targets
|
||||
url(r"^submit_member$", member_submit),
|
||||
url(r"^update_member$", member_update),
|
||||
url(r"^delete_member$", member_delete),
|
||||
url(r"^submit_payment$", payment_submit),
|
||||
url(r"^update_payment$", payment_update),
|
||||
url(r"^delete_payment$", payment_delete),
|
||||
url(r"^submit_application$", application_submit),
|
||||
url(r"^accept_application$", application_accept),
|
||||
url(r"^delete_application$", application_delete),
|
||||
re_path(r"^submit_member$", member_submit),
|
||||
re_path(r"^update_member$", member_update),
|
||||
re_path(r"^delete_member$", member_delete),
|
||||
re_path(r"^submit_payment$", payment_submit),
|
||||
re_path(r"^update_payment$", payment_update),
|
||||
re_path(r"^delete_payment$", payment_delete),
|
||||
re_path(r"^submit_application$", application_submit),
|
||||
re_path(r"^accept_application$", application_accept),
|
||||
re_path(r"^delete_application$", application_delete),
|
||||
# the actual member application form
|
||||
url(r"^application/$", application_form),
|
||||
re_path(r"^application/$", application_form),
|
||||
# delete confirmation view for applications
|
||||
url(r"^delete_application_confirm/(?P<index>\d+)$", application_delete_confirm),
|
||||
re_path(r"^delete_application_confirm/(?P<index>\d+)$", application_delete_confirm),
|
||||
# list all payment events
|
||||
url(r"^payments$", payment_list),
|
||||
re_path(r"^payments$", payment_list),
|
||||
# add payment event
|
||||
url(r"^add_payment$", payment_add),
|
||||
re_path(r"^add_payment$", payment_add),
|
||||
# edit payment event
|
||||
url(r"^edit_payment/(?P<index>\d+)$", payment_edit),
|
||||
re_path(r"^edit_payment/(?P<index>\d+)$", payment_edit),
|
||||
# delete confirmation view
|
||||
url(r"^delete_payment_confirm/(?P<index>\d+)$", payment_delete_confirm),
|
||||
re_path(r"^delete_payment_confirm/(?P<index>\d+)$", payment_delete_confirm),
|
||||
# post endpoint for confirming multiple entries
|
||||
url(r"^add_many_confirm$", add_many_confirm),
|
||||
re_path(r"^add_many_confirm$", add_many_confirm),
|
||||
# settings page
|
||||
url(r"^settings$", settings_page),
|
||||
re_path(r"^settings$", settings_page),
|
||||
# send CSV member data by POST
|
||||
url(r"^import_csv", import_csv),
|
||||
re_path(r"^import_csv", import_csv),
|
||||
# export members as excel file
|
||||
url(r"export_members", export_members_excel),
|
||||
url(r"export_payments", export_payments_excel),
|
||||
url(r"export_applications", export_applications_excel),
|
||||
re_path(r"export_members", export_members_excel),
|
||||
re_path(r"export_payments", export_payments_excel),
|
||||
re_path(r"export_applications", export_applications_excel),
|
||||
# rest api url
|
||||
url(r"^api/members/(?P<pk>\d+)$", MemberDetail.as_view()),
|
||||
re_path(r"^api/members/(?P<pk>\d+)$", MemberDetail.as_view()),
|
||||
# member select autocomplete view
|
||||
url(
|
||||
re_path(
|
||||
r"^member-autocomplete/$",
|
||||
MemberAutoComplete.as_view(),
|
||||
name="member-autocomplete",
|
||||
),
|
||||
url(r"^check", CheckByEmail.as_view()),
|
||||
re_path(r"^check", CheckByEmail.as_view()),
|
||||
]
|
||||
|
||||
if settings.DEBUG:
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
"""File containing Members application views."""
|
||||
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
@@ -4,7 +4,7 @@ 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.conf import settings
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.translation import gettext as _
|
||||
from django.forms.models import model_to_dict
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ from django.http import (
|
||||
HttpResponseForbidden,
|
||||
)
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.translation import gettext as _
|
||||
from django.forms.models import model_to_dict
|
||||
from dal import autocomplete
|
||||
from django.utils import timezone
|
||||
@@ -249,7 +249,7 @@ class MemberAutoComplete(autocomplete.Select2QuerySetView):
|
||||
if self.q:
|
||||
qs = Member.find_members_by_name(self.q)
|
||||
|
||||
return qs
|
||||
return qs.order_by("last_name")
|
||||
|
||||
|
||||
class CheckByEmail(APIView):
|
||||
|
||||
@@ -4,7 +4,7 @@ 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.conf import settings
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.translation import gettext as _
|
||||
from django.forms.models import model_to_dict
|
||||
|
||||
import logging
|
||||
|
||||
@@ -4,7 +4,7 @@ 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.conf import settings
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.translation import gettext as _
|
||||
from django.forms.models import model_to_dict
|
||||
from django_tables2.config import RequestConfig
|
||||
|
||||
@@ -135,7 +135,7 @@ def import_csv(request, *args, **kwargs):
|
||||
member_table = MemberTable(
|
||||
result.members,
|
||||
request=request,
|
||||
exclude=["id", "options"],
|
||||
exclude=["id", "options", "last_paid"],
|
||||
attrs={"class": "table table-bordered table-hover"},
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
"""File containing Ohlhafv forms."""
|
||||
|
||||
from django import forms
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.core.exceptions import ValidationError
|
||||
|
||||
from ohlhafv.models import OhlhafvChallenge
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@ 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.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.contrib.auth.models import User
|
||||
from auditlog.registry import auditlog
|
||||
from phonenumber_field.modelfields import PhoneNumberField
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
|
||||
.navbar-border {
|
||||
border-bottom: 2px solid #282b3b;
|
||||
border-radius: 0px 0px 8px 8px;
|
||||
}
|
||||
|
||||
.navbar-light .navbar-nav .nav-link {
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 56 KiB |
+1
-1
@@ -1,6 +1,6 @@
|
||||
import django_tables2 as tables
|
||||
from django.db.models import Count, Q
|
||||
from django.utils.translation import ugettext as _
|
||||
from django.utils.translation import gettext as _
|
||||
|
||||
from ohlhafv.models import OhlhafvChallenge
|
||||
|
||||
|
||||
+5
-5
@@ -1,16 +1,16 @@
|
||||
"""Ohlhafv urls."""
|
||||
|
||||
from django.conf.urls import url
|
||||
from django.urls import re_path
|
||||
from django.conf import settings
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
|
||||
from ohlhafv.views import *
|
||||
|
||||
urlpatterns = [
|
||||
# ohlhafv
|
||||
url(r"^submit", ohlhafv_submit),
|
||||
url(r"^list", ohlhafv_list),
|
||||
url(r"^$", ohlhafv_view),
|
||||
re_path(r"^submit", ohlhafv_submit),
|
||||
re_path(r"^list", ohlhafv_list),
|
||||
re_path(r"^$", ohlhafv_view),
|
||||
]
|
||||
|
||||
if settings.DEBUG:
|
||||
|
||||
+1
-1
@@ -3,7 +3,7 @@ from django.shortcuts import render
|
||||
from django.views.decorators.http import require_http_methods
|
||||
from django.views.decorators.csrf import ensure_csrf_cookie
|
||||
from django.http import HttpResponseRedirect
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.template.loader import render_to_string
|
||||
|
||||
from sikweb.settings import URL
|
||||
|
||||
Generated
+4756
-3742
File diff suppressed because it is too large
Load Diff
+9
-7
@@ -9,7 +9,7 @@
|
||||
"lint:py": "black --diff --check .",
|
||||
"lint:py:fix": "black .",
|
||||
"lint:py-type": "pyright",
|
||||
"prepare": "husky install"
|
||||
"prepare": "husky"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@@ -17,13 +17,15 @@
|
||||
},
|
||||
"author": "SIK ry",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"eslint": "^7.28.0",
|
||||
"husky": "^6.0.0",
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^9.20.0",
|
||||
"eslint": "^9.20.0",
|
||||
"globals": "^15.14.0",
|
||||
"husky": "^9.1.7",
|
||||
"npm-run-all": "^4.1.5",
|
||||
"pyright": "^1.1.149",
|
||||
"remark-cli": "^9.0.0",
|
||||
"remark-preset-lint-recommended": "^5.0.0"
|
||||
"pyright": "^1.1.393",
|
||||
"remark-cli": "^12.0.1",
|
||||
"remark-preset-lint-recommended": "^7.0.1"
|
||||
},
|
||||
"remarkConfig": {
|
||||
"plugins": [
|
||||
|
||||
Generated
+1262
-627
File diff suppressed because it is too large
Load Diff
@@ -39,4 +39,4 @@ 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
|
||||
gunicorn --log-level debug -w 4 -b 0.0.0.0:8000 sikweb.wsgi
|
||||
|
||||
+53
-42
@@ -1,49 +1,60 @@
|
||||
[tool.poetry]
|
||||
name = "web2.0-backend"
|
||||
version = "0.1.0"
|
||||
[project]
|
||||
authors = [
|
||||
{name = "Aarni Halinen", email = "aarni.halinen@sahkoinsinoorikilta.fi"},
|
||||
]
|
||||
description = "Backend for sahkoinsinoorikilta.fi"
|
||||
authors = ["Aarni Halinen aarni.halinen@sahkoinsinoorikilta.fi"]
|
||||
name = "web2.0-backend"
|
||||
readme = "README.md"
|
||||
requires-python = ">=3.12"
|
||||
version = "0.1.0"
|
||||
|
||||
[tool.poetry.dependencies]
|
||||
python = "^3.9"
|
||||
decorator = "^4.0.9"
|
||||
Django = "^3.2.14"
|
||||
requests = "^2.28.1"
|
||||
django-cors-headers = "^3.13.0"
|
||||
djangorestframework = "^3.12.4"
|
||||
psycopg2-binary = "^2.9.3"
|
||||
django-bootstrap3 = "^21.2"
|
||||
django-tables2 = "^2.4.1"
|
||||
django-modeltranslation = "^0.18.4"
|
||||
django-auditlog = "^2.1.1"
|
||||
django-phonenumber-field = {version = "^6.3.0", extras = ["phonenumbers"]}
|
||||
django-autocomplete-light = "^3.4.1"
|
||||
six = "^1.12.0"
|
||||
pyexcel = "^0.5.14"
|
||||
pyexcel-xlsx = "^0.5.8"
|
||||
django-import-export = "^2.8.0"
|
||||
openpyxl = "^2.6.4"
|
||||
django-app-namespace-template-loader = "^0.4.1"
|
||||
django-filter = "^22.1"
|
||||
whitenoise = "^6.2.0"
|
||||
jsonschema = "^4.9.0"
|
||||
Markdown = "^3.2.2"
|
||||
uWSGI = "^2.0.18"
|
||||
gunicorn = "^20.1.0"
|
||||
Pillow = "^9.1.1"
|
||||
sendgrid = "^6.7.0"
|
||||
sentry-sdk = "^1.4.3"
|
||||
django-polymorphic = "^3.1.0"
|
||||
python-dotenv = "^0.20.0"
|
||||
djangorestframework-simplejwt = "^5.2.0"
|
||||
google-auth = "^2.9.1"
|
||||
google-api-python-client = "^2.54.0"
|
||||
dependencies = [
|
||||
"decorator (>=4.4.2,<5.0.0)",
|
||||
"Django (>=4.2.19,<5.0.0)",
|
||||
"django-app-namespace-template-loader (>=0.4.1,<1.0.0)",
|
||||
"django-auditlog (>=2.1.1,<3.0.0)",
|
||||
"django-autocomplete-light (>=3.4.1,<4.0.0)",
|
||||
"django-bootstrap3 (>=21.2.0,<22.0.0)",
|
||||
"django-cors-headers (>=3.13.0,<4.0.0)",
|
||||
"django-filter (>=22.1.0,<23.0.0)",
|
||||
"django-import-export (>=2.8.0,<3.0.0)",
|
||||
"django-modeltranslation (>=0.18.4,<1.0.0)",
|
||||
"django-phonenumber-field[phonenumbers] (>=6.4.0,<7.0.0)",
|
||||
"django-polymorphic (>=3.1.0,<4.0.0)",
|
||||
"django-tables2 (>=2.4.1,<3.0.0)",
|
||||
"djangorestframework (>=3.12.4,<4.0.0)",
|
||||
"djangorestframework-simplejwt (>=5.2.0,<6.0.0)",
|
||||
"google-auth (>=2.9.1,<3.0.0)",
|
||||
"google-api-python-client (>=2.54.0,<3.0.0)",
|
||||
"gunicorn (>=20.1.0,<21.0.0)",
|
||||
"jsonschema (>=4.9.0,<5.0.0)",
|
||||
"Markdown (>=3.2.2,<4.0.0)",
|
||||
"openpyxl (>=2.6.4,<3.0.0)",
|
||||
"Pillow (>=10.0.0,<11.0.0)",
|
||||
"psycopg2-binary (>=2.9.3,<3.0.0)",
|
||||
"pyexcel (>=0.7.0,<1.0.0)",
|
||||
"pyexcel-io (>=0.6.0,<1.0.0)",
|
||||
"pyexcel-xlsx (>=0.6.0,<1.0.0)",
|
||||
"python-dotenv (>=0.20.0,<1.0.0)",
|
||||
"requests (>=2.28.1,<3.0.0)",
|
||||
"sendgrid (>=6.7.0,<7.0.0)",
|
||||
"sentry-sdk (>=1.4.3,<2.0.0)",
|
||||
"six (>=1.12.0,<2.0.0)",
|
||||
"uWSGI (>=2.0.28,<3.0.0)",
|
||||
"whitenoise (>=6.2.0,<7.0.0)",
|
||||
]
|
||||
|
||||
[tool.poetry.dev-dependencies]
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
black = "^25.1.0"
|
||||
coverage = "^6.4.2"
|
||||
safety = "^2.1.1"
|
||||
black = "^22.6.0"
|
||||
safety = "^2.3.4"
|
||||
|
||||
[tool.poetry]
|
||||
package-mode = false
|
||||
|
||||
[tool.poetry.requires-plugins]
|
||||
poetry-plugin-export = "^1.9"
|
||||
|
||||
[build-system]
|
||||
requires = ["poetry-core>=1.0.0"]
|
||||
requires = ["poetry-core>=2.0.0,<3.0.0"]
|
||||
build-backend = "poetry.core.masonry.api"
|
||||
|
||||
+1
-1
@@ -12,5 +12,5 @@
|
||||
"reportMissingImports": true,
|
||||
"reportMissingTypeStubs": false,
|
||||
|
||||
"pythonVersion": "3.9"
|
||||
"pythonVersion": "3.12.9"
|
||||
}
|
||||
+1
-1
@@ -2,7 +2,7 @@ import os
|
||||
import logging
|
||||
import datetime
|
||||
from os.path import expanduser
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_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__)))
|
||||
|
||||
+13
-28
@@ -1,23 +1,6 @@
|
||||
"""sikweb URL Configuration
|
||||
|
||||
The `urlpatterns` list routes URLs to views. For more information please see:
|
||||
https://docs.djangoproject.com/en/1.9/topics/http/urls/
|
||||
Examples:
|
||||
Function views
|
||||
1. Add an import: from my_app import views
|
||||
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
|
||||
Class-based views
|
||||
1. Add an import: from other_app.views import Home
|
||||
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
|
||||
Including another URLconf
|
||||
1. Add an import: from blog import urls as blog_urls
|
||||
2. Import the include() function: from django.conf.urls import url, include
|
||||
3. Add a URL to urlpatterns: url(r'^blog/', include(blog_urls))
|
||||
"""
|
||||
from django.conf.urls import url
|
||||
from django.urls import re_path, include
|
||||
from django.contrib import admin
|
||||
from django.views.static import serve as static_serve
|
||||
from django.conf.urls import include
|
||||
from django.conf.urls.static import static
|
||||
from django.conf import settings
|
||||
from django.contrib.staticfiles import views as static_views
|
||||
@@ -27,18 +10,20 @@ favicon_view = RedirectView.as_view(url="static/img/favicon.png", permanent=True
|
||||
|
||||
|
||||
urlpatterns = [
|
||||
url(r"", include("webapp.urls")),
|
||||
url(r"^members/", include("members.urls")),
|
||||
url(r"^infoscreen/", include("infoscreen.urls")),
|
||||
url(r"^kaehmy/", include("kaehmy.urls")),
|
||||
url(r"^ohlhafv/", include("ohlhafv.urls")),
|
||||
re_path(r"", include("webapp.urls")),
|
||||
re_path(r"^members/", include("members.urls")),
|
||||
re_path(r"^infoscreen/", include("infoscreen.urls")),
|
||||
re_path(r"^kaehmy/", include("kaehmy.urls")),
|
||||
re_path(r"^ohlhafv/", include("ohlhafv.urls")),
|
||||
# favourite icon
|
||||
url(r"^favicon\.ico$", favicon_view),
|
||||
re_path(r"^favicon\.ico$", favicon_view),
|
||||
# admin
|
||||
url(r"^admin/", admin.site.urls),
|
||||
re_path(r"^admin/", admin.site.urls),
|
||||
# i18n default view for changing the active language
|
||||
url(r"^i18n/", include("django.conf.urls.i18n")),
|
||||
re_path(r"^i18n/", include("django.conf.urls.i18n")),
|
||||
# staticfiles default view for static files in development
|
||||
url(r"^static/(?P<path>.*)$", static_views.serve),
|
||||
url(r"^media/(?P<path>.*)$", static_serve, {"document_root": settings.MEDIA_ROOT}),
|
||||
re_path(r"^static/(?P<path>.*)$", static_views.serve),
|
||||
re_path(
|
||||
r"^media/(?P<path>.*)$", static_serve, {"document_root": settings.MEDIA_ROOT}
|
||||
),
|
||||
] + static(settings.STATIC_URL, document_root=settings.STATIC_ROOT)
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
</div>
|
||||
<div class="kaehmy-banner heading">
|
||||
<p style="color:#D57A2D; font-size:2rem">{% blocktrans %}Kähmyt ovat auki!{% endblocktrans %}</p>
|
||||
<p style="color:#BFDBD9; font-size:1rem">{% blocktrans %}Haku hallitukseen 24.10. mennessä ja toimihenkilöksi 18.11 mennessä.{% endblocktrans %}</p>
|
||||
<p style="color:#BFDBD9; font-size:1rem">{% blocktrans %}Haku hallitukseen 23.10. mennessä ja toimihenkilöksi 15.11 mennessä.{% endblocktrans %}</p>
|
||||
<p style="color:#BFDBD9; font-size:1.5rem">{% blocktrans %}Hae nyt!{% endblocktrans %}</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -28,12 +28,11 @@
|
||||
</p>
|
||||
<h5>{% trans "Päivämääriä & deadlineja" %}</h5>
|
||||
<ul>
|
||||
<li><strong>11.10.</strong> {% blocktrans %}Toimikuntamessut @OK20{% endblocktrans %}</li>
|
||||
<li><strong>24.10.</strong> {% blocktrans %}Deadline hallitusvirkoihin hakemiselle.{% endblocktrans %}</li>
|
||||
<li><strong>25.10.</strong> {% blocktrans %}Vaalikokous, osa 1 (puheenjohtajan valinta) ja hallitustyrkkypaneeli{% endblocktrans %}</li>
|
||||
<li><strong>07.11.</strong> {% blocktrans %}Vaalikokous, osa 2 (hallituksen valinta){% endblocktrans %}</li>
|
||||
<li><strong>18.11.</strong> {% blocktrans %}Deadline toimivirkoihin hakemiselle.{% endblocktrans %}</li>
|
||||
<li><strong>24.11.</strong> {% blocktrans %}Vaalikokous, osa 3 (toimarien valinta){% endblocktrans %}</li>
|
||||
<li><strong>23.10.</strong> {% blocktrans %}Deadline hallitusvirkoihin hakemiselle.{% endblocktrans %}</li>
|
||||
<li><strong>24.10.</strong> {% blocktrans %}Vaalikokous, osa 1 (puheenjohtajan valinta) ja hallitustyrkkypaneeli{% endblocktrans %}</li>
|
||||
<li><strong>6.11.</strong> {% blocktrans %}Vaalikokous, osa 2 (hallituksen ja toimikuntien puheenjohtajien valinta){% endblocktrans %}</li>
|
||||
<li><strong>15.11.</strong> {% blocktrans %}Deadline toimivirkoihin hakemiselle.{% endblocktrans %}</li>
|
||||
<li><strong>21.11.</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 %}
|
||||
@@ -80,6 +79,7 @@
|
||||
Hyväksyn <a href="https://static.sahkoinsinoorikilta.fi/GDPR/Tietosuojaseloste%20%E2%80%93%20Toimihenkil%C3%B6ksi%20hakemisen%20rekisteri.pdf" target="_blank">tietosuojaselosteen</a> ja tietojeni tallentamisen.
|
||||
{% endblocktrans %}
|
||||
</span>
|
||||
<br>
|
||||
{% buttons %}
|
||||
<button type="submit" class="btn btn-primary">
|
||||
{% trans "Submit" %}
|
||||
|
||||
@@ -7,5 +7,5 @@
|
||||
<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ä admin@sahkoinsinoorikilta.fi jos viestiä ei näy." %}</p>
|
||||
<a href="https://sahkoinsinoorikilta.fi/"><h4>{% trans "Takaisin Sähköinsinöörikillan web-sivuille" %}</h4></a>
|
||||
<a href="https://sahkoinsinoorikilta.fi/"><h4>{% trans "Takaisin Sähköinsinöörikillan etusivulle" %}</h4></a>
|
||||
{% endblock content %}
|
||||
|
||||
@@ -9,7 +9,5 @@
|
||||
tulevia tapahtumia ja piipahda kiltahuoneella tutustumassa uusiin kiltatovereihisi!
|
||||
</p>
|
||||
|
||||
<p>Liity myös killan TG-kanaville:</p>
|
||||
<p><a href="https://t.me/+ubTeGSYKTvg3NmVk">Killan yleinen telegram</a></p>
|
||||
<p><a href="https://t.me/+1PqQHRVMjiAxMTU0">SIK-fuksit 2022</a></p>
|
||||
<p><a href="https://t.me/+Ln8TvQ-_id9kZTU0">SIK-fuksit 2022 -tiedotuskanava</a></p>
|
||||
<p>Liity myös killan TG-kanavalle:</p>
|
||||
<p><a href="https://t.me/+AB-JMbAxM2c0MDc0">Killan yleinen telegram</a></p>
|
||||
@@ -5,6 +5,6 @@
|
||||
|
||||
{{ challenge.message }}
|
||||
|
||||
{% trans "Muistattehan vahvistaa haasteen paikan päällä Smökissä torstaina 26.5" %}.
|
||||
{% trans "Muistattehan vahvistaa haasteen paikan päällä Smökissä torstaina 13.2" %}.
|
||||
|
||||
{% trans "Käy kurkkaamassa muutkin haasteet osoitteessa" %} {{ url }}
|
||||
@@ -3,6 +3,6 @@
|
||||
|
||||
<div class="ohlhafv-header-content">
|
||||
<div class="ohlhafv-banner logo">
|
||||
<a href="/ohlhafv"><img class="ohlhafv-banner-image" src="{% static "ohlhafv/img/heevit.jpg" %}" alt="Aalto-yliopiston Sähköinsinöörikilta ry"></a>
|
||||
<a href="/ohlhafv"><img class="ohlhafv-banner-image" src="{% static "ohlhafv/img/heevi_banner.svg" %}" alt="Aalto-yliopiston Sähköinsinöörikilta ry"></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -6,4 +6,4 @@
|
||||
|
||||
<a href={{ url }}>{{url}}</a>
|
||||
|
||||
<p>Hädässä ota yhteyttä admin@sahkoinsinoorikilta.fi</p>
|
||||
<p>Hädässä ota yhteyttä tapahtuman järjestään.</p>
|
||||
|
||||
+1
-1
@@ -10,7 +10,7 @@ from django.dispatch import receiver
|
||||
import requests
|
||||
from uuid import uuid4
|
||||
import logging
|
||||
from django.utils.translation import ugettext_lazy as _
|
||||
from django.utils.translation import gettext_lazy as _
|
||||
from django.db.models import JSONField
|
||||
from auditlog.registry import auditlog
|
||||
from polymorphic.models import PolymorphicModel
|
||||
|
||||
@@ -2,6 +2,7 @@ from django.contrib.auth.models import User, AnonymousUser
|
||||
from django.utils import timezone
|
||||
from rest_framework import status
|
||||
from rest_framework.test import APITestCase, APIRequestFactory
|
||||
import zoneinfo
|
||||
|
||||
from webapp.models import Event
|
||||
from webapp.serializers import EventSerializer
|
||||
@@ -14,28 +15,30 @@ URL = "/api/events/"
|
||||
|
||||
class EventTestCase(APITestCase):
|
||||
def setUp(self):
|
||||
tz = zoneinfo.ZoneInfo(key="Europe/Helsinki")
|
||||
# Visible and relevant
|
||||
test1 = createEventObject(
|
||||
"Testitapahtuma1", start_time=timezone.datetime(2019, 11, 9, 12, 0, 0)
|
||||
"Testitapahtuma1",
|
||||
start_time=timezone.datetime(2019, 11, 9, 12, 0, 0, tzinfo=tz),
|
||||
)
|
||||
# Invisible but relevant
|
||||
createEventObject(
|
||||
"Testitapahtuma2",
|
||||
visible=False,
|
||||
start_time=timezone.datetime(2018, 11, 9, 12, 0, 0),
|
||||
start_time=timezone.datetime(2018, 11, 9, 12, 0, 0, tzinfo=tz),
|
||||
)
|
||||
# Visible but unrelevant
|
||||
test2 = createEventObject(
|
||||
"Testitapahtuma3",
|
||||
visible=True,
|
||||
start_time=timezone.datetime(2018, 12, 9, 12, 0, 0),
|
||||
end_time=timezone.datetime(2018, 12, 9, 13, 0, 0),
|
||||
start_time=timezone.datetime(2018, 12, 9, 12, 0, 0, tzinfo=tz),
|
||||
end_time=timezone.datetime(2018, 12, 9, 13, 0, 0, tzinfo=tz),
|
||||
)
|
||||
# Visible and relevant
|
||||
createEventObject(
|
||||
"Testitapahtuma4",
|
||||
visible=True,
|
||||
start_time=timezone.datetime(2018, 12, 9, 12, 0, 0),
|
||||
start_time=timezone.datetime(2018, 12, 9, 12, 0, 0, tzinfo=tz),
|
||||
)
|
||||
# Add some tags
|
||||
tag1 = tagBuilder()
|
||||
@@ -77,7 +80,9 @@ class EventTestCase(APITestCase):
|
||||
self.assertEqual(response.data["results"], expected)
|
||||
|
||||
def test_get_events_since(self):
|
||||
response = self.client.get(f"{URL}?since=2018-01-01", format="json")
|
||||
response = self.client.get(
|
||||
f"{URL}?since=2018-01-01%2000:00:00%2B0200", format="json"
|
||||
)
|
||||
self.assertTrue(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(len(response.data["results"]), 3)
|
||||
|
||||
|
||||
@@ -22,13 +22,6 @@ class SignupTestCase(APITestCase):
|
||||
|
||||
self.signup1 = createSignupObject("1", self.signupForm, ALL_QUESTION_TYPES)
|
||||
self.signup2 = createSignupObject("2", self.signupForm, ALL_QUESTION_TYPES)
|
||||
self.signup_admin_delete = createSignupObject(
|
||||
"3", self.signupForm, ALL_QUESTION_TYPES
|
||||
)
|
||||
self.signup_user_delete = createSignupObject(
|
||||
"4", self.signupForm, ALL_QUESTION_TYPES
|
||||
)
|
||||
self.signup_count = 4
|
||||
|
||||
username, password = "test_admin", "password123"
|
||||
self.authClient = User.objects.create_superuser(
|
||||
@@ -56,17 +49,17 @@ class SignupTestCase(APITestCase):
|
||||
new = createSignupRequest("asd", self.signupForm.id, ALL_QUESTION_TYPES_ANSWER)
|
||||
response = self.client.post(URL, new, format="json")
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||
self.assertEqual(Signup.objects.count(), self.signup_count + 1)
|
||||
self.assertEqual(Signup.objects.count(), 3)
|
||||
|
||||
# Can signup to a hidden form
|
||||
def test_create_signup_hidden(self):
|
||||
new = createSignupRequest("asd", self.hiddenForm.id, ALL_QUESTION_TYPES_ANSWER)
|
||||
response = self.client.post(URL, new, format="json")
|
||||
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
|
||||
self.assertEqual(Signup.objects.count(), self.signup_count + 1)
|
||||
self.assertEqual(Signup.objects.count(), 3)
|
||||
|
||||
def test_delete_as_admin(self):
|
||||
id = self.signup_admin_delete.id
|
||||
id = self.signup1.id
|
||||
no_auth_response = self.client.delete(f"{URL}{id}/", format="json")
|
||||
self.assertEqual(no_auth_response.status_code, status.HTTP_401_UNAUTHORIZED)
|
||||
self.client.force_authenticate(user=self.authClient)
|
||||
@@ -88,18 +81,9 @@ class SignupTestCase(APITestCase):
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(Signup.objects.get(id=id).answer["-naY2R1-h"], "Edited Testi")
|
||||
|
||||
def test_delete_as_user(self):
|
||||
bad_uuid = "d5a98794-8330-45b4-8ed4-cdb84198649b"
|
||||
id = self.signup_user_delete.id
|
||||
uuid = self.signup_user_delete.uuid
|
||||
|
||||
no_auth_response = self.client.delete(f"{URL}{id}/delete/?uuid={bad_uuid}")
|
||||
self.assertEqual(no_auth_response.status_code, status.HTTP_404_NOT_FOUND)
|
||||
self.assertEqual(Signup.objects.get(id=id).deleted, False)
|
||||
|
||||
response = self.client.delete(f"{URL}{id}/delete/?uuid={uuid}")
|
||||
self.assertEqual(response.status_code, status.HTTP_200_OK)
|
||||
self.assertEqual(Signup.objects.get(id=id).deleted, True)
|
||||
@skip("NotImplemented")
|
||||
def test_delete_signup_token(self):
|
||||
pass
|
||||
|
||||
# TODO: Use some mocking library and check that sendgrid is actually called
|
||||
def test_signupee_sendemail(self):
|
||||
|
||||
+3
-4
@@ -1,7 +1,6 @@
|
||||
"""Webapp urls."""
|
||||
|
||||
from django.conf.urls import url, include
|
||||
from django.urls import path
|
||||
from django.urls import path, re_path, include
|
||||
from rest_framework import routers
|
||||
from rest_framework_simplejwt.views import (
|
||||
TokenObtainPairView,
|
||||
@@ -25,9 +24,9 @@ router.register(r"tags", TagsViewSet)
|
||||
router.register(r"jobads", JobAdViewSet)
|
||||
|
||||
urlpatterns = [
|
||||
url(r"^api/", include(router.urls)),
|
||||
re_path(r"^api/", include(router.urls)),
|
||||
path(r"api/token/", TokenObtainPairView.as_view(), name="token_obtain_pair"),
|
||||
path(r"api/token/verify/", TokenVerifyView.as_view(), name="token_verify"),
|
||||
path(r"api/token/refresh/", TokenRefreshView.as_view(), name="token_refresh"),
|
||||
url(r"^jwt_nginx", nginx_jwt_resp),
|
||||
re_path(r"^jwt_nginx", nginx_jwt_resp),
|
||||
]
|
||||
|
||||
+1
-21
@@ -200,13 +200,7 @@ class SignupViewSet(ModelViewSet):
|
||||
serializer_class = SignupSerializer
|
||||
permission_classes = [SignupPermission]
|
||||
|
||||
@action(
|
||||
url_path="edit",
|
||||
url_name="edit",
|
||||
detail=True,
|
||||
methods=["get", "put"],
|
||||
permission_classes=[AllowAny],
|
||||
)
|
||||
@action(detail=True, methods=["get", "put"], permission_classes=[AllowAny])
|
||||
def edit(self, request, pk=None, *args, **kwargs):
|
||||
uuid = request.query_params.get("uuid", None)
|
||||
queryset = self.filter_queryset(self.get_queryset())
|
||||
@@ -217,20 +211,6 @@ class SignupViewSet(ModelViewSet):
|
||||
elif request.method == "PUT":
|
||||
return self.partial_update(request, *args, **kwargs)
|
||||
|
||||
@action(
|
||||
url_path="delete",
|
||||
url_name="delete",
|
||||
detail=True,
|
||||
methods=["delete"],
|
||||
permission_classes=[AllowAny],
|
||||
)
|
||||
def user_delete(self, request, pk=None, *args, **kwargs):
|
||||
uuid = request.query_params.get("uuid", None)
|
||||
queryset = self.filter_queryset(self.get_queryset())
|
||||
filter = {"pk": pk, "uuid": uuid}
|
||||
get_object_or_404(queryset, **filter)
|
||||
return self.destroy(request, *args, **kwargs)
|
||||
|
||||
def create(self, request, *args, **kwargs):
|
||||
id = request.data["signupForm_id"]
|
||||
try:
|
||||
|
||||
Reference in New Issue
Block a user