243 Commits

Author SHA1 Message Date
Simeon Pursiainen 8164094b44 Edit email.html 2025-01-23 19:13:16 +00:00
Simeon Pursiainen fd12f35e2e Update .gitlab-ci.yml file 2025-01-23 19:09:37 +00:00
Simeon Pursiainen f69615437a Edit email.html 2025-01-23 19:06:02 +00:00
Simeon Pursiainen 533f367b4e Edit Hafv date 2025-01-21 21:18:06 +00:00
Simeon Pursiainen 93202d8a11 skip ci 2025-01-21 20:59:13 +00:00
Simeon Pursiainen e1e1adc397 Changed date for 2025 Hafv 2025-01-21 13:15:02 +00:00
tommi s 0df2d4ab46 Merge branch 'develop' into 'master'
Develop to master

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!98
2023-10-05 13:45:16 +00:00
Tommi S 4e0a93631d Compiled translations 2023-10-05 16:20:28 +03:00
Tommi S be9e308587 update kaeyhmy categories and add english kaehmyguide 2023-10-05 14:25:22 +03:00
tommi s 738051355b Merge branch 'develop' into 'master'
fixes

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!97
2023-10-04 18:02:38 +00:00
Tommi S 8550a9a02b prkl 2023-10-04 20:46:06 +03:00
tommi s 1cf67c7686 Merge branch 'develop' into 'master'
Edit signup email contact address

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!96
2023-10-04 17:26:31 +00:00
Tommi S 703bb91bfd Edit signup email contact 2023-10-04 20:04:20 +03:00
tommi s 2ff0cab544 Merge branch 'develop' into 'master'
Kaehmy dates update

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!95
2023-10-03 20:42:29 +00:00
Tommi S 6b4a00ebd8 Edit text 2023-10-03 23:30:34 +03:00
Tommi S 677c1400fa Fix lines 2023-10-03 00:08:08 +03:00
Tommi S a2e08d0ea6 Update kaehmy header dates 2023-10-02 23:23:32 +03:00
tommi s 901f2bed96 Merge branch 'feature/disable_kaehmybot_button' into 'develop'
Add kaehmybot disable button

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!94
2023-10-02 20:05:24 +00:00
Tommi S 6004156b6f Add kaehmybot disable button 2023-10-01 17:34:01 +03:00
Tommi S e00323bffe Update readme docker database name 2023-09-29 21:27:38 +03:00
Tommi S 6ef0dbf91b Update kaehmy dates 2023-09-29 20:10:39 +03:00
tommi s 2169bad90d Merge branch 'develop' into 'master'
Develop to master

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!93
2023-09-15 09:21:19 +00:00
Tommi S 63a4781574 Edit accepting message 2023-09-15 12:02:31 +03:00
Tommi S e735ebe64a Merge branch 'develop' of gitlab.com:sahkoinsinoorikilta/vtmk/web2.0-backend into develop 2023-09-14 17:54:48 +03:00
Tommi S f9db8476a1 Does it work now 2023-09-14 17:52:54 +03:00
tommi s 2a24544056 Update deprecated variables 2023-09-14 14:39:38 +00:00
Tommi S fb7bee5480 Update djangorestframework 2023-09-14 15:33:19 +03:00
Tommi S 8355d10635 Update django, requests, sentry-sdk, sqlparse 2023-09-14 11:35:59 +03:00
Tommi S 21892e277e Update certifi 2023-09-14 11:28:58 +03:00
Tommi S 81e1f994eb Update tg-channel link and remove freshmen groups from accepting email 2023-09-13 19:03:49 +03:00
Aarni Halinen c79d824a8a Merge branch 'develop' into 'master'
Prod deploy: Add log level to gunicorn

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!92
2023-03-27 16:30:59 +00:00
Aarni Halinen fc6e02b71b Add log level to gunicorn 2023-03-27 19:16:08 +03:00
Ilari Ojakorpi 1e14f98f9d Merge branch 'develop' into 'master'
Develop

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!91
2023-03-05 18:03:40 +00:00
Ojakoo 8815ccf667 update django 2023-03-05 19:53:44 +02:00
Ojakoo b694370572 :D 2023-03-05 19:35:51 +02:00
Ilari Ojakorpi f51611bbee Merge branch 'develop' into 'master'
Develop to Master

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!90
2023-02-07 14:58:52 +00:00
Ojakoo fda9acfb2f update certifi 2023-02-07 16:43:02 +02:00
Ojakoo 30c6e4809b update hafv page 2023-02-07 16:35:07 +02:00
Ilari Ojakorpi 4373f37dfe Merge branch 'develop' into 'master'
Merge Develop to master

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!89
2022-12-29 13:53:51 +00:00
Ilari Ojakorpi 39754a5e63 Merge branch 'django-v4' into 'develop'
Draft: Django v4

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!72
2022-12-25 13:10:34 +00:00
Ojakoo 0be3ee69be add ordering to remove pagination error 2022-12-24 21:07:46 +02:00
Ojakoo c6f0f4615b lint 2022-12-24 20:59:07 +02:00
Ojakoo 3ac5400b79 updated pyexcel packages 2022-12-24 20:55:40 +02:00
Ojakoo 429d3a0602 make datetimes aware 2022-12-23 13:16:39 +02:00
Ojakoo 1b086843dc Update poetry 2022-12-21 19:16:55 +02:00
Ojakoo b9280ea026 update protobuf 2022-12-21 18:59:27 +02:00
Ojakoo b36022e546 Update django 2022-12-21 18:57:33 +02:00
Ojakoo 9bb57840a7 Update pillow 2022-12-21 18:55:49 +02:00
Ojakoo 36bd74c6cc Revert some merge stuff 2022-12-21 18:44:43 +02:00
Ojakoo a2615ae27d Merge branch 'develop' into django-v4 2022-12-21 18:34:39 +02:00
Ojakoo f7de9e32d3 remove last_paid column to not search database for unexisting entries 2022-12-21 18:13:54 +02:00
Ojakoo 57d8c4321f Update readme. 2022-12-21 16:20:59 +02:00
Aarni Halinen 632eedea9c Test scheduled job 2022-10-31 22:36:28 +02:00
Aarni Halinen 1405d89d9a Test scheduled job 2022-10-31 22:21:45 +02:00
Aarni Halinen da1ae8d721 Test scheduled job 2022-10-31 22:19:30 +02:00
Aarni Halinen 52a83b9336 Scheduled job for Docker cleanup 2022-10-24 21:58:39 +03:00
Aarni Halinen f67ce55d60 Fix webapp test as module 2022-10-24 21:42:41 +03:00
Ilari Ojakorpi d8fdc2cc74 Merge branch 'develop' into 'master'
Changes to kaehmy categories

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!86
2022-10-05 11:24:00 +00:00
Ojakoo 5e1390ab6b Changes to kaehmy categories 2022-10-05 14:18:28 +03:00
Ilari Ojakorpi eb2ae3368a Merge branch 'develop' into 'master'
Develop to master

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!85
2022-10-05 10:08:08 +00:00
Ojakoo 99348dc297 Update dparse 2022-10-05 12:58:29 +03:00
Ojakoo 715b309c89 Added new categories for kaehmy 2022-10-05 12:43:52 +03:00
Ilari Ojakorpi f7f63b8670 Merge branch 'develop' into 'master'
Use html templates for kaehmy emails. No translations for now.

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!84
2022-09-23 18:01:33 +00:00
Ojakoo 70676d5203 Lint 2022-09-23 20:53:25 +03:00
Ojakoo 037e4ae6e8 Use html templates for kaehmy emails. No translations for now. 2022-09-23 20:30:08 +03:00
Ilari Ojakorpi 53742e5caa Merge branch 'develop' into 'master'
Update kaehmy page

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!83
2022-09-23 15:29:08 +00:00
Ojakoo 8d6f13b61d Update privacy policy link 2022-09-23 17:57:36 +03:00
Ojakoo 03982ee620 Update kaehmy dates and change header to html instead of picture. 2022-09-23 17:51:01 +03:00
Ilari Ojakorpi 2affae7bfd Merge branch 'develop' into 'master'
Develop

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!82
2022-09-19 08:09:20 +00:00
Ojakoo a8923b63d6 wrap private key 2022-09-13 13:31:58 +03:00
Ojakoo 19975877cb Remove debug stuff 2022-09-13 09:59:55 +03:00
Ojakoo 2e0fad4bb2 Use POSIX format for source 2022-09-12 22:42:01 +03:00
Ojakoo f0179c1840 Change google creds format. Ugly but works. 2022-09-12 22:38:18 +03:00
Ojakoo 37a9750d4d Add group key and dev secrets to stack compose 2022-09-05 13:38:26 +03:00
Ojakoo 5575186570 lint 2022-09-05 12:03:31 +03:00
Ojakoo 9e179d5e06 Added error handling for incorrectly formatted google creds 2022-09-05 10:40:29 +03:00
Ilari Ojakorpi f7659e1e1b Merge branch 'develop' into 'master'
Modified paths

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!81
2022-08-17 20:53:54 +00:00
Ojakoo ea9a732803 Modified paths 2022-08-17 23:00:11 +03:00
Ilari Ojakorpi a4ae136e1a Merge branch 'develop' into 'master'
juuh eli

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!80
2022-08-16 20:07:54 +00:00
Ojakoo 0026b788b2 juuh eli 2022-08-16 23:00:36 +03:00
Ilari Ojakorpi 570fff1d7d Merge branch 'develop' into 'master'
Totally works now

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!79
2022-08-16 19:33:24 +00:00
Ojakoo da3a484f6c wbn? 2022-08-16 22:24:20 +03:00
Ilari Ojakorpi 9d116528b9 Merge branch 'develop' into 'master'
Develop

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!78
2022-08-16 18:49:48 +00:00
Ojakoo a310d51f5e or not 2022-08-16 21:43:04 +03:00
Ojakoo 6732e30213 #14 fix paths 2022-08-16 21:26:55 +03:00
Ilari Ojakorpi afbdca1501 Merge branch 'develop' into 'master'
Enable GOOGLE_SERVICE_ACCOUNT, should work now..

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!77
2022-08-16 18:14:50 +00:00
Ojakoo 4e59eee200 Enable GOOGLE_SERVICE_ACCOUNT, should work now.. 2022-08-16 20:59:19 +03:00
Aarni Halinen 03e4ccdf5d Merge branch 'develop' into 'master'
Prod deploy: Fix kaehmy form

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!76
2022-08-11 08:36:29 +00:00
Aarni Halinen bb0b2a2628 Fix kaehmy form 2022-08-11 11:28:30 +03:00
Aarni Halinen 16454ebdf6 Merge branch 'develop' into 'master'
Prod deploy: Disable GOOGLE_SERVICE_ACCOUNT for debugging

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!75
2022-08-11 07:00:05 +00:00
Aarni Halinen 32d636d3ee Disable GOOGLE_SERVICE_ACCOUNT for debugging 2022-08-11 09:52:58 +03:00
Ilari Ojakorpi 2e2464fb5f Merge branch 'develop' into 'master'
dumdum

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!74
2022-08-09 18:55:55 +00:00
Ojakoo c91b99cdb1 lol 2022-08-09 21:44:01 +03:00
Ilari Ojakorpi caf2113e49 Merge branch 'develop' into 'master'
Merge 'develop' into' master'

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!71
2022-08-09 14:11:42 +00:00
Aarni Halinen c1a1f6e534 Replace deprecated functions 2022-08-06 16:54:16 +03:00
Aarni Halinen f79d1467f7 Install Django v4 2022-08-06 16:38:28 +03:00
Aarni Halinen 40cf9121b6 Clean-up README and coveragerc 2022-08-06 16:35:58 +03:00
Aarni Halinen ca73eba609 Revert "Install django-suit v2"
This reverts commit fe46d57108.
2022-08-06 16:26:15 +03:00
Aarni Halinen fe46d57108 Install django-suit v2 2022-08-06 16:02:58 +03:00
Ojakoo 70e1835a4f Update dependencies 2022-08-06 12:28:43 +03:00
Ojakoo b7f17671d9 Resolve conlict 2022-08-06 12:09:50 +03:00
Ojakoo 34659403a8 lint 2022-08-06 11:03:39 +03:00
Ojakoo 4fbf5fe0a4 Jas list error notification only in prod 2022-08-06 10:17:43 +03:00
Ojakoo c6be0e6562 Add google envs to deploy 2022-08-06 10:07:00 +03:00
Aarni Halinen 3623c7e9f4 Fix TG message template 2022-08-04 00:51:45 +03:00
Aarni Halinen 298db5b78e Merge branch 'remove-baserole' into 'develop'
Remove webapp BaseRole model

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!67
2022-08-03 20:44:55 +00:00
Aarni Halinen 1ca6de3090 Fix lint 2022-08-03 23:35:41 +03:00
Aarni Halinen 07d0f2aa47 Remove comment 2022-08-03 23:19:42 +03:00
Aarni Halinen 93e122b8a8 Remove webapp BaseRole 2022-08-03 23:19:40 +03:00
Aarni Halinen 9678b663a0 Update kaehmy BaseRole 2022-08-03 23:18:32 +03:00
Aarni Halinen 992a2ec8e0 Add new BaseRole 2022-08-03 23:15:12 +03:00
Aarni Halinen b41bd41a54 Fix typo 2022-08-03 23:11:49 +03:00
Aarni Halinen 30f59c36fb Clean-up templates 2022-08-03 22:57:19 +03:00
Aarni Halinen f51d71e045 Fix most of html templates 2022-08-03 22:46:14 +03:00
Ojakoo 9c66238b82 Remove old json route 2022-08-03 00:34:42 +03:00
Ilari Ojakorpi 2f0143a9ae Merge branch 'update-django' into 'develop'
Update Django

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!68
2022-08-02 21:31:05 +00:00
Ojakoo 45ff2c3757 Format datetime to local timezone 2022-08-03 00:20:23 +03:00
Aarni Halinen 321d45b628 Fix unit tests 2022-08-01 22:31:47 +03:00
Aarni Halinen 2628d753f5 Fix JSONField deprecation warning 2022-08-01 22:22:30 +03:00
Aarni Halinen a603e2dff8 Add explicit primary keys 2022-08-01 22:22:02 +03:00
Aarni Halinen 96e05d908d Fix static files 2022-08-01 22:00:12 +03:00
Aarni Halinen a5bf5668eb Remove django-suit 2022-08-01 21:50:07 +03:00
Aarni Halinen 1ec5082faf Update Django packages 2022-08-01 21:33:31 +03:00
Aarni Halinen 6da5b97e19 Remove template tags removed in Django v3 2022-08-01 21:30:17 +03:00
Aarni Halinen 7fd30e3eba Update DB settings for Django v3 2022-08-01 21:24:10 +03:00
Aarni Halinen 3e9084ca1d Update jsonschema 2022-08-01 21:16:56 +03:00
Aarni Halinen a28f82d31e Update whitenoise 2022-08-01 21:15:08 +03:00
Aarni Halinen 04ecb8fc7e Update requests 2022-08-01 21:14:47 +03:00
Aarni Halinen 3e707e58a5 Run poetry update 2022-08-01 21:12:17 +03:00
Aarni Halinen 70d7f55996 Remove nose test runner 2022-08-01 21:09:17 +03:00
Aarni Halinen e408809e58 Update dev tools 2022-08-01 21:02:15 +03:00
Ojakoo 33fd4012f1 #13 fixed homepage link 2022-08-01 00:24:34 +03:00
Ojakoo 228938b695 lint 2022-07-31 16:33:28 +03:00
Ojakoo 72e91e3d62 Moved google creds to .env 2022-07-31 16:28:57 +03:00
Ojakoo 3f6a719e9d Added error handling, send email to user if adding fails 2022-07-31 11:12:51 +03:00
Aarni Halinen 490b99a848 Fix schema type 2022-07-28 22:13:01 +03:00
Aarni Halinen 0a899f5600 Fix schema 2022-07-28 21:45:48 +03:00
Aarni Halinen 7825cc7293 Add form validation on update 2022-07-28 21:16:22 +03:00
Aarni Halinen 8bb6e9e9a7 Add input validation schema for SignupFormViewSet create 2022-07-28 21:13:09 +03:00
Ojakoo 53c3acd39f directory api working state 2022-07-25 20:12:32 +03:00
Aarni Halinen c45bcc5442 Merge branch 'develop' into 'master'
Prod deploy: Fix Filebrowser authentication cookie

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!66
2022-07-24 18:26:38 +00:00
Aarni Halinen dd0254a08e fix try-catch for jwt verification 2022-07-24 21:02:35 +03:00
Aarni Halinen 9b53fb4bc0 use jwt_access cookie in Filebrowser auth 2022-07-24 20:53:21 +03:00
Aarni Halinen 2383e2089d Merge branch 'develop' into 'master'
Prod deploy: Add algorithms for FileBrowser JWT verification

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!65
2022-07-24 17:35:33 +00:00
Aarni Halinen e17c3ad92c Add --without-hashes to poetry export in Dockerfile 2022-07-22 01:08:36 +03:00
Aarni Halinen 362d981532 Disable pip dependency resolver in Dockerfile (handled by poetry) 2022-07-22 00:55:19 +03:00
Aarni Halinen e12be3c2f6 Revert "Add --without-hashes to poetry export in Dockerfile"
This reverts commit 3edae7f967.
2022-07-22 00:54:38 +03:00
Aarni Halinen 3edae7f967 Add --without-hashes to poetry export in Dockerfile 2022-07-22 00:52:04 +03:00
Aarni Halinen 4d159b2793 Add algorithms for FileBrowser JWT verification 2022-07-22 00:13:37 +03:00
Aarni Halinen cb3b831f7a Use husky for pre-commit hook 2022-07-21 23:47:56 +03:00
Aarni Halinen acba330694 Update CORS setting 2022-07-21 23:37:32 +03:00
Aarni Halinen eb22368055 Cleanup settings 2022-07-21 23:28:06 +03:00
Ilari Ojakorpi 5f467323b5 Merge branch 'develop' into 'master'
Merge 'Develop' into master

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!64
2022-07-06 19:50:50 +00:00
Ojakoo fac2f9b367 Added pre-commit linter, lint 2022-07-04 10:33:38 +03:00
Ojakoo 7319c32d73 lint 2022-07-04 10:24:53 +03:00
Ojakoo b3a484ce55 Added verify path 2022-07-04 10:19:40 +03:00
Ojakoo 337b774074 lint 2022-06-21 21:47:54 +03:00
Ojakoo e70e598c57 #12 Changed djangorestframework-jwt to djangorestframework-simplejwt 2022-06-21 21:35:59 +03:00
Ojakoo 5eef2f685c Update pyjwt 2022-06-20 22:17:29 +03:00
Ojakoo d1953ef24c Changed application accept email formatting to html 2022-06-20 16:44:06 +03:00
Ilari Ojakorpi a9c122c0d4 Merge branch 'develop' into 'master'
heevi email fix

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!62
2022-05-26 09:28:20 +00:00
Ojakoo ec4317d9e7 heevi email fix 2022-05-25 19:13:16 +03:00
Ilari Ojakorpi d4a219290b Merge branch 'develop' into 'master'
Merge develop into master

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!61
2022-05-22 23:08:42 +00:00
Ojakoo cff84816fc Updated member application email links 2022-05-23 01:53:05 +03:00
Ojakoo 7881a24eb1 Updated heevi email message 2022-05-23 01:52:30 +03:00
Ilari Ojakorpi e74580fdde Merge branch 'develop' into 'master'
Merge develop into master

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!60
2022-05-19 20:58:32 +00:00
Aarni Halinen a0765ca18b Merge branch 'python-dotenv' into 'develop'
Python dotenv

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!56
2022-05-19 19:23:14 +00:00
Aarni Halinen 913eb1cedf load .env file 2022-05-19 22:19:07 +03:00
Aarni Halinen 7035ebccca install python-dotenv 2022-05-19 22:18:50 +03:00
Aarni Halinen 2031146fc7 Merge branch 'add-dockerignore' into 'develop'
Add dockerignore file

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!59
2022-05-19 19:15:11 +00:00
Aarni Halinen 35f30300b3 Merge branch 'remove-about-page' into 'develop'
Remove about page

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!58
2022-05-19 19:13:58 +00:00
Aarni Halinen 342f2862a5 force empty logs and media folders 2022-05-19 22:11:36 +03:00
Aarni Halinen 3536ca5922 add dockerignore 2022-05-19 22:11:36 +03:00
Aarni Halinen 50ab7bc1f9 remove dealer 2022-05-19 22:09:47 +03:00
Aarni Halinen 102d8f82d6 remove about page 2022-05-19 22:08:18 +03:00
Aarni Halinen f302c0a17d Merge branch 'fix-audit' into 'develop'
Fix audit

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!57
2022-05-19 18:52:17 +00:00
Aarni Halinen a2b7086e9a update poetry to 1.1.13 2022-05-19 21:44:15 +03:00
Aarni Halinen 704652c643 update linter 2022-05-19 21:37:54 +03:00
Aarni Halinen 8741f6b113 update Pillow 2022-05-19 21:33:19 +03:00
Aarni Halinen 9ffb79aa52 poetry update 2022-05-19 21:32:37 +03:00
Ojakoo a2551cc110 Changed heevi banner 2022-05-19 15:44:32 +03:00
Aarni Halinen 8c90471eb1 Merge branch 'develop' into 'master'
Prod deploy: Webhooks (new TG bot setup)

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!55
2022-01-14 00:50:18 +00:00
Aarni Halinen 8d7bd7067e remove TG_BOT_TOKEN 2022-01-14 00:14:32 +02:00
Aarni Halinen db3e3ae291 remove TG_BOT_TOKEN 2022-01-14 00:14:13 +02:00
Aarni Halinen fc73424665 Merge branch 'develop' into 'master'
Prod deploy: Fix Ohlhafv emails

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!52
2022-01-13 20:12:13 +00:00
Aarni Halinen b610a8af6e Merge branch 'develop' into 'master'
Prod deploy: Disable sentry performance monitoring

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!51
2021-11-17 17:30:51 +00:00
Toni Lyttinen 6022b11dc1 Merge branch 'develop' into 'master'
Prod deploy: Sentry & update Ohlhafv page

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!49
2021-11-17 16:22:34 +00:00
Oskari Ponkala 72ea31a887 Merge branch 'develop' into 'master'
Develop

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!47
2021-10-05 08:44:31 +00:00
Oskari Ponkala 40b824355b Merge branch 'develop' into 'master'
Develop

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!45
2021-06-01 08:45:26 +00:00
Aarni Halinen 5f69f34bf3 Merge branch 'develop' into 'master' 2021-05-16 18:43:23 +03:00
Aarni Halinen c0db047cd9 Merge branch 'develop' into 'master' 2021-05-16 18:18:00 +03:00
Aarni Halinen e2c32e81a7 Merge branch 'develop' into 'master'
Prod deploy: Python 3.9, poetry & dependency updates, SendGrid, Managed DB

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!41
2021-05-16 14:54:43 +00:00
Toni Lyttinen 6a65ca32d7 Merge branch 'develop' into 'master'
Merge feed list order fix to master

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!39
2021-04-08 10:22:38 +00:00
Aarni Halinen 99739cd035 Merge branch 'develop' into 'master'
1st Live deploy

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!37
2021-03-31 21:02:11 +00:00
Aarni Halinen 8454e67a92 Merge branch 'develop' into 'master'
Prod deploy

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!36
2021-03-30 17:08:29 +00:00
Aarni Halinen 33c7c20140 Merge branch 'develop' into 'master'
Prod deploy

* Soft deletes

* sahkoinsinoorikilta.fi domain

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!34
2021-01-19 15:42:22 +00:00
Aarni Halinen 5a77b1546d Merge branch 'develop' into 'master'
Azure deploy & Signup flow

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!32
2020-12-12 12:11:09 +00:00
Toni Lyttinen 81971b6da4 Merge branch 'develop' into 'master'
added "toimikunta-appro" date to kaehmy.html

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!28
2020-10-28 13:39:45 +00:00
Toni Lyttinen a68fa9a6d6 Merge branch 'develop' into 'master'
Kaehmy fix Merge

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!27
2020-10-20 18:43:07 +00:00
Toni Lyttinen 034e04a788 Merge branch 'develop' into 'master'
Merge kaehmy changes to master

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!26
2020-10-07 08:48:06 +00:00
Aarni Halinen d416fda39e Merge branch 'develop' into 'master'
SIK100 Seminar email hack

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!23
2020-08-31 01:11:31 +00:00
Aarni Halinen e4fbb58026 Merge branch 'develop' into 'master'
API serializers for signups

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!22
2020-08-29 12:09:55 +00:00
Aarni Halinen 56dfd57698 Merge branch 'develop' into 'master'
Serialize SignupForm visible

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!20
2020-07-25 09:23:14 +00:00
Aarni Halinen 8632aa01da Merge branch 'develop' into 'master'
Signup modifications to production

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!19
2020-07-24 19:29:20 +00:00
Aarni Halinen 8b1f668d38 Merge branch 'develop' into 'master'
Dependency bump, move volumes under static file server

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!17
2020-03-05 19:21:53 +00:00
Toni Lyttinen 027bf5e7bd Merge branch 'develop' into 'master'
Color updates to Ohlhalv

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!16
2020-02-02 14:42:40 +00:00
Toni Lyttinen be22fea3f2 Merge branch 'develop' into 'master'
Updated ohlhafv challenge buttoncolor to match the page background

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!15
2020-02-02 14:26:23 +00:00
Toni Lyttinen 5e434408b0 Merge branch 'develop' into 'master'
New Ohlhafv graphics

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!14
2020-02-02 14:00:17 +00:00
Toni Lyttinen 41762e920f Updated background color to match image 2020-02-02 13:10:41 +00:00
Aarni Halinen f390e1fb1f Merge branch 'develop' into 'master'
api.sika.sik.party

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!13
2019-12-18 18:39:27 +00:00
Aarni Halinen 4e35a73a4b Merge branch 'develop' into 'master'
Update admin login url

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!12
2019-12-17 19:44:45 +00:00
Aarni Halinen 6955659acb Merge branch 'develop' into 'master'
Add filebrowser

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!11
2019-12-17 17:24:04 +00:00
Aarni Halinen dbc7811651 Merge branch 'develop' into 'master'
Update PG, Hackathon commits

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!10
2019-12-17 16:39:12 +00:00
Aarni Halinen 6c4a26eb44 Merge branch 'develop' 2019-10-10 01:05:24 +03:00
Aarni Halinen fb9dbe2cd2 Merge branch 'develop' 2019-10-10 00:46:11 +03:00
Aarni Halinen b346c2122a Merge branch 'develop' into 'master'
Python 3.7 and path fixes

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!7
2019-10-09 21:11:12 +00:00
Aarni Halinen c9c814e405 Merge branch 'develop' 2019-10-09 22:21:57 +03:00
Aarni Halinen 0f72a7ea21 Merge branch 'develop' 2019-10-09 21:18:16 +03:00
Aarni Halinen 135c0309b5 Merge branch 'develop' 2019-10-09 19:33:45 +03:00
Aarni Halinen bd4551a222 Merge branch 'develop' 2019-10-09 19:03:50 +03:00
Aarni Halinen 7fee47f150 Merge branch 'develop' 2019-10-08 23:16:19 +03:00
Aarni Halinen b0dd95fa86 Merge branch 'develop' 2019-10-08 22:17:28 +03:00
Aarni Halinen 9516dbbbea Merge branch 'develop' 2019-10-08 20:55:09 +03:00
Aarni Halinen 5b2546217c Merge branch 'develop' 2019-10-08 19:57:06 +03:00
Aarni Halinen 2646914b8a Merge branch 'develop' 2019-10-08 19:43:01 +03:00
Aarni Halinen 17c00e519b Merge branch 'develop' 2019-10-08 13:04:42 +03:00
Aarni Halinen 389771d106 Merge branch 'develop' 2019-10-08 12:41:51 +03:00
Aarni Halinen ed4e226186 Merge branch 'develop' 2019-10-08 10:19:30 +03:00
Aarni Halinen bc7a8ebd17 Merge branch 'develop' 2019-10-08 10:01:29 +03:00
Aarni Halinen cfdac40d3b Merge branch 'develop' 2019-10-08 09:41:07 +03:00
Aarni Halinen ec4be22552 Merge branch 'develop' 2019-10-08 01:00:41 +03:00
Aarni Halinen 06d5e3c6f4 Merge branch 'develop' 2019-10-08 00:46:46 +03:00
Aarni Halinen 89cd91dbad Merge branch 'develop' 2019-10-08 00:32:54 +03:00
Aarni Halinen 44c091f2d5 Merge branch 'develop' 2019-10-08 00:05:15 +03:00
Aarni Halinen c1b3bedf8d Merge branch 'develop' 2019-10-07 23:53:24 +03:00
Aarni Halinen 3c16029e88 Merge branch 'develop' 2019-10-07 22:03:17 +03:00
Aarni Halinen 41d6f17716 Merge branch 'develop' 2019-10-07 21:28:27 +03:00
Aarni Halinen 2649afdd4b Merge branch 'develop' 2019-10-07 21:19:28 +03:00
Aarni Halinen 8ee514326a Merge branch 'develop' 2019-10-07 21:10:43 +03:00
Aarni Halinen 48e34ece4f Merge branch 'develop' 2019-10-07 20:31:48 +03:00
Aarni Halinen d2af34bf0c Merge branch 'develop' 2019-10-07 19:59:34 +03:00
Aarni Halinen ddf4ad7b8d Merge branch 'develop' 2019-10-07 19:57:32 +03:00
Aarni Halinen 3169191a0d Merge branch 'develop' into 'master'
New Sika & Membership application

See merge request sahkoinsinoorikilta/vtmk/web2.0-backend!3
2019-10-07 16:04:32 +00:00
151 changed files with 4189 additions and 3263 deletions
-4
View File
@@ -1,9 +1,5 @@
[report]
show_missing = True
omit =
*/migrations/*
*/admin.py
*/translation.py
[run]
omit =
*/migrations/*
+32
View File
@@ -0,0 +1,32 @@
.DS_Store
.dockerignore
.git/
.husky/
.venv/
.vscode/
collected_static/
logs/
!logs/README
media/
!media/REMOVE_ME
misc/
node_modules/
scripts/
.coverage
.coveragerc
.env*
.eslintignore
.eslintrc.json
.gitignore
.gitlab-ci.yml
.python-version
docker-compose.yml
!manage.py
package*.json
!poetry.lock
!production_entrypoint.sh
pycodestyle.cfg
!pyproject.toml
pyright.json
README.md
stack-compose*.yml
+4 -3
View File
@@ -1,12 +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(
TG_BOT_TOKEN=
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='{}'
+2 -1
View File
@@ -3,10 +3,11 @@ DEPLOY_ENV=local
HOST=localhost
DEBUG=True
SECRET_KEY=7p$85^4ibb^p4-=vs44b7!y0e-zemugze18@a#30&71=a8)dp(
TG_BOT_TOKEN=
DB_NAME=postgres
DB_USER=postgres
DB_PASSWD=postgres
DB_HOST=db
DB_PORT=5432
EMAIL_API_KEY=
GROUP_KEY=
GOOGLE_CREDS='{}'
+1 -1
View File
@@ -11,4 +11,4 @@ node_modules/
.idea/
*.code-workspace
venv/
.venv/
.venv/
+68 -8
View File
@@ -5,10 +5,13 @@ stages:
- test
- publish
- deploy
- cleanup
install:
image: node:14
stage: setup
only:
- pushes
script:
- npm ci
artifacts:
@@ -19,9 +22,14 @@ install:
audit:
image: python:3.9
stage: audit
only:
- pushes
- develop
except:
- master
needs: []
before_script:
- pip install poetry==1.1.4
- pip install poetry==1.3.1
- poetry config virtualenvs.create false
- poetry install --no-interaction --no-ansi
script:
@@ -30,6 +38,8 @@ audit:
test:
image: python:3.9
stage: test
only:
- pushes
needs: []
services:
- postgres:12
@@ -40,7 +50,7 @@ test:
DATABASE_URL: "postgresql://postgres:postgres@postgres:5432/$POSTGRES_DB"
DB_HOST: postgres
before_script:
- pip install poetry==1.1.4
- pip install poetry==1.3.1
- poetry config virtualenvs.create false
- poetry install --no-interaction --no-ansi
script:
@@ -51,14 +61,18 @@ test:
lint:py:
image: python:3.9
stage: lint
only:
- pushes
needs: []
script:
- pip install black==21.12b0
- pip install black==22.3.0
- black --check .
lint:js:
image: node:14
stage: lint
only:
- pushes
needs: ["install"]
script:
- npm run lint:js
@@ -66,13 +80,15 @@ lint:js:
lint:md:
image: node:14
stage: lint
only:
- pushes
needs: ["install"]
script:
- npm run lint:md
publish:
stage: publish
image: docker:stable
stage: publish
needs: ["test", "lint:py", "lint:js", "lint:md"]
services:
- docker:stable-dind
@@ -86,8 +102,8 @@ publish:
- docker push "$IMAGE_NAME"
deploy:dev:
stage: deploy
image: docker:stable
stage: deploy
only:
- develop
environment:
@@ -101,7 +117,7 @@ deploy:dev:
- 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"
- 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:
@@ -124,8 +140,52 @@ deploy:production:
- 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"
- 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 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"
+15
View File
@@ -0,0 +1,15 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
PURPLE='\033[0;35m'
NC='\033[0m' # No Color
. "${VIRTUAL_ENV}/bin/activate"
if [ $? -ne 0 ]
then
printf "${PURPLE}Failed to find virtualenv. Skipping pre-commit hook.\n${NC}"
exit 0
fi
npm run lint
+1 -1
View File
@@ -4,7 +4,7 @@
PURPLE='\033[0;35m'
NC='\033[0m' # No Color
source "${VIRTUAL_ENV}/bin/activate"
. "${VIRTUAL_ENV}/bin/activate"
if [ $? -ne 0 ]
then
+3 -3
View File
@@ -2,10 +2,10 @@ FROM python:3.9-slim-buster as builder
ENV PYTHONUNBUFFERED 1
COPY . ./
ENV POETRY_VERSION=1.1.4
ENV POETRY_VERSION=1.3.1
RUN pip install "poetry==$POETRY_VERSION"
RUN poetry export > requirements.txt
RUN poetry export --without-hashes > requirements.txt
FROM python:3.9-slim-buster as server
@@ -22,7 +22,7 @@ ENV PYTHONUNBUFFERED=1 \
PIP_DEFAULT_TIMEOUT=100
RUN apt-get update && apt-get install --no-install-recommends -y build-essential
RUN pip install -r requirements.txt
RUN pip install --no-deps -r requirements.txt
RUN python manage.py collectstatic --noinput
CMD ["sh", "-c", "./production_entrypoint.sh"]
+47 -39
View File
@@ -1,24 +1,13 @@
# 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
### 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
* **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.
## Installation
Set up your SSH key authentication in GitLab Profile Settings. Then clone the repository and checkout the development branch:
@@ -28,14 +17,19 @@ 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
python3 -m pip install poetry==1.3.1
```
The easiest integration with VSCode is to have poetry install virtual environment in project folder, configured with CMD
@@ -44,9 +38,26 @@ The easiest integration with VSCode is to have poetry install virtual environmen
python3 -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:
```
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
@@ -60,20 +71,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 +88,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 +103,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 +114,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 +146,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`.
@@ -0,0 +1,28 @@
# Generated by Django 3.2.14 on 2022-08-01 19:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("infoscreen", "0007_lunchitem"),
]
operations = [
migrations.AlterField(
model_name="infoinstance",
name="id",
field=models.AutoField(primary_key=True, serialize=False),
),
migrations.AlterField(
model_name="infoitem",
name="id",
field=models.AutoField(primary_key=True, serialize=False),
),
migrations.AlterField(
model_name="rotation",
name="id",
field=models.AutoField(primary_key=True, serialize=False),
),
]
+6 -1
View File
@@ -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):
@@ -16,6 +16,7 @@ class InfoItem(models.Model):
class __meta__:
abstract = True
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255)
# expire_date = None means never expiring item
expire_date = models.DateTimeField(blank=True, null=True)
@@ -316,6 +317,7 @@ class ExternalImageInfoItem(InfoItem):
class InfoInstance(models.Model):
"""Class for Info instance in Infoscreen."""
id = models.AutoField(primary_key=True)
rotation = models.ForeignKey(
"Rotation", related_name="instances", on_delete=models.CASCADE
)
@@ -356,6 +358,7 @@ class InfoInstance(models.Model):
class Rotation(models.Model):
"""Class for rotation model."""
id = models.AutoField(primary_key=True)
name = models.CharField(max_length=255)
def get_dict(self):
@@ -388,6 +391,7 @@ class Rotation(models.Model):
class ImageUploadForm(forms.Form):
"""Form used to handle imageuploads to infoscreen app."""
id = models.AutoField(primary_key=True)
name = forms.CharField()
image = forms.ImageField()
@@ -395,5 +399,6 @@ class ImageUploadForm(forms.Form):
class UploadFileForm(forms.Form):
"""Form used for uploading file."""
id = models.AutoField(primary_key=True)
name = forms.CharField()
video = forms.FileField()
+1 -1
View File
@@ -3,7 +3,7 @@ body {
}
#header:after {
content: " ";
content: " ";
display: block;
clear: both;
}
+2 -2
View File
@@ -12,7 +12,7 @@ body {
.event {
font-size: 100px;
font-weight: bold;
margin-left: 20px;
margin-left: 20px;
}
.event-col{
padding-top:1vh;
@@ -21,7 +21,7 @@ body {
.header-row{
margin: 30px;
margin-left: 20px;
margin-left: 20px;
font-size: 130px;
padding-bottom:20px;
color:#24a05f;
@@ -1,8 +1,8 @@
#infocontent {
width: 100%;
height: 100%;
position: fixed;
left: 0px;
width: 100%;
height: 100%;
position: fixed;
left: 0px;
top: 0px;
z-index: -1; /* Ensure div tag stays behind content; -999 might work, too. */
}
+3 -3
View File
@@ -31,10 +31,10 @@
max-height 200px;
}
#sossoimage {
#sossoimage {
height:300px;
position: relative;
left: 0px;
position: relative;
left: 0px;
top: 0px;
}
@@ -1,5 +1,5 @@
<link rel="stylesheet" href="/static/infoscreen/css/events.css">
<link href="https://fonts.googleapis.com/css?family=Droid+Sans+Mono" rel="stylesheet">
<link href="https://fonts.googleapis.com/css?family=Droid+Sans+Mono" rel="stylesheet">
<div class="container" ng-app="myApp" ng-controller="EventController">
<div class="header-row row">
<div class="col-sm-6">Tapahtuma</div>
+23 -23
View File
@@ -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
View File
@@ -36,7 +36,7 @@ from infoscreen.models import (
@permission_required("infoscreen.change_infoinstance", raise_exception=True)
def admin(request, *args, **kwargs):
"""Render infoscreen admin page."""
return render(request, "infoscreen:infoscreen_admin.html", {})
return render(request, "infoscreen/infoscreen_admin.html", {})
def create_item_generator(model):
+1 -1
View File
@@ -15,7 +15,7 @@ import requests
@require_http_methods(["GET"])
def index(request, idx, *args, **kwargs):
"""Render infoscreen index page."""
return render(request, "infoscreen_index.html", {"rotation": idx})
return render(request, "infoscreen/infoscreen_index.html", {"rotation": idx})
@require_http_methods(["GET"])
+6 -6
View File
@@ -1,20 +1,20 @@
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, KaehmyBaseRole
from kaehmy.models import PresetRole, CustomRole, Application, Comment, BaseRole
class CheckboxSelectMultiple(forms.widgets.CheckboxSelectMultiple):
option_template_name = "checkbox_option.html"
def create_option(
self, name, value, label, selected, index, subindex=None, attrs=None
self, name, formIterator, label, selected, index, subindex=None, attrs=None
):
dic = super(CheckboxSelectMultiple, self).create_option(
name, value, label, selected, index, subindex, attrs
name, formIterator, label, selected, index, subindex, attrs
)
description = PresetRole.objects.get(id=value).description
description = PresetRole.objects.get(id=formIterator.value).description
dic["description"] = description
return dic
@@ -57,7 +57,7 @@ class ApplicationForm(forms.ModelForm):
self.fields["custom_roles"].label = _("Custom roles")
self.fields["custom_roles"].queryset = CustomRole.objects.all()
for cat_id, category in KaehmyBaseRole.CATEGORIES:
for cat_id, category in BaseRole.CATEGORIES:
key = "preset_roles_{}".format(cat_id)
qset = PresetRole.objects.filter(category=cat_id).order_by(
"category", "-is_board"
@@ -0,0 +1,18 @@
# Generated by Django 3.2.14 on 2022-08-01 19:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("kaehmy", "0006_delete_telegramchannel"),
]
operations = [
migrations.AlterField(
model_name="commentparent",
name="id",
field=models.AutoField(primary_key=True, serialize=False),
),
]
+44
View File
@@ -0,0 +1,44 @@
# Generated by Django 3.2.14 on 2022-08-03 20:14
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("kaehmy", "0007_alter_commentparent_id"),
]
operations = [
migrations.CreateModel(
name="BaseRole",
fields=[
("id", models.AutoField(primary_key=True, serialize=False)),
("name", models.CharField(max_length=255, verbose_name="Name")),
("is_board", models.BooleanField(verbose_name="Board member")),
(
"category",
models.CharField(
choices=[
("corporate", "Corporate affairs"),
("freshman", "Freshmen"),
("international", "International"),
("external", "External affairs"),
("media", "Media"),
("tech", "Technology"),
("wellbeing", "Wellbeing"),
("elepaja", "Elepaja"),
("ceremonies", "Ceremonies"),
("studies", "Studies"),
("sosso", "Sössö magazine"),
("alumni", "Alumni relations"),
("others", "Others"),
],
default="others",
max_length=255,
verbose_name="Category",
),
),
],
),
]
@@ -0,0 +1,29 @@
# Generated by Django 2.2.28 on 2022-07-26 17:15
from unicodedata import category
from django.db import migrations
def copyBaseRolesToNewTable(apps, schema_editor):
Old = apps.get_model("kaehmy", "KaehmyBaseRole")
New = apps.get_model("kaehmy", "BaseRole")
for bases in Old.objects.all():
New.objects.create(
id=bases.id,
name=bases.name,
is_board=bases.is_board,
category=bases.category,
)
class Migration(migrations.Migration):
dependencies = [
("kaehmy", "0008_baserole"),
]
operations = [
migrations.RunPython(
copyBaseRolesToNewTable, reverse_code=migrations.RunPython.noop
),
]
@@ -0,0 +1,51 @@
# Generated by Django 2.2.28 on 2022-07-26 17:33
from django.db import migrations, models
import django.db.models.deletion
from sikweb.custom_operations import AlterModelBases
class Migration(migrations.Migration):
dependencies = [
("kaehmy", "0009_auto_20220726_2015"),
]
operations = [
AlterModelBases("customrole", (models.Model,)),
AlterModelBases("presetrole", (models.Model,)),
migrations.AlterField(
model_name="customrole",
name="kaehmybaserole_ptr",
field=models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="BaseRole",
),
),
migrations.AlterField(
model_name="presetrole",
name="kaehmybaserole_ptr",
field=models.OneToOneField(
auto_created=True,
on_delete=django.db.models.deletion.CASCADE,
parent_link=True,
primary_key=True,
serialize=False,
to="BaseRole",
),
),
migrations.RenameField(
model_name="customrole",
old_name="kaehmybaserole_ptr",
new_name="baserole_ptr",
),
migrations.RenameField(
model_name="presetrole",
old_name="kaehmybaserole_ptr",
new_name="baserole_ptr",
),
]
@@ -0,0 +1,16 @@
# Generated by Django 3.2.14 on 2022-08-03 20:19
from django.db import migrations
class Migration(migrations.Migration):
dependencies = [
("kaehmy", "0010_auto_20220726_2033"),
]
operations = [
migrations.DeleteModel(
name="KaehmyBaseRole",
),
]
+19 -15
View File
@@ -1,42 +1,45 @@
from django.db import models
from django.utils import timezone
from django.utils.translation import ugettext_lazy as _
from webapp.models import BaseRole
# 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
from django.utils.translation import gettext_lazy as _
VERBOSE_NAME = _("Kaehmy")
class KaehmyBaseRole(BaseRole):
"""ABC"""
class BaseRole(models.Model):
"""Base model for occupations/roles."""
id = models.AutoField(primary_key=True)
name = models.CharField(_("Name"), max_length=255)
is_board = models.BooleanField(_("Board member"))
CATEGORIES = (
("board", _("Board")),
("corporate", _("Corporate affairs")),
("freshman", _("Freshmen")),
("international", _("International")),
("external", _("External affairs")),
("siwa", _("SIK's free time")),
("media", _("Media")),
("tech", _("Technology")),
("wellbeing", _("Wellbeing")),
("elepaja", _("Elepaja")),
("sikpaja", _("Sik-paja")),
("ceremonies", _("Ceremonies")),
("studies", _("Studies")),
("sosso", _("Sössö magazine")),
("pota", _("PoTa")),
("alumni", _("Alumni relations")),
("n", _("N")),
("others", _("Others")),
)
category = models.CharField(
_("Category"), choices=CATEGORIES, default="others", max_length=255
)
def __str__(self):
n = self.name.capitalize()
return "{} ({})".format(n, _("board member")) if self.is_board else n
class PresetRole(KaehmyBaseRole):
class PresetRole(BaseRole):
"""Model for kaehmy role."""
description = models.TextField(_("Description"))
@@ -46,7 +49,7 @@ class PresetRole(KaehmyBaseRole):
verbose_name_plural = _("Preset kaehmy roles")
class CustomRole(KaehmyBaseRole):
class CustomRole(BaseRole):
"""Model representing a user-specified custom occupation."""
class Meta:
@@ -56,6 +59,7 @@ class CustomRole(KaehmyBaseRole):
class CommentParent(models.Model):
id = models.AutoField(primary_key=True)
name = models.CharField(_("Name"), max_length=255, default="")
email = models.EmailField(_("Email"), default="")
timestamp = models.DateTimeField(_("Timestamp"), default=timezone.now)
+4 -6
View File
@@ -5,12 +5,6 @@
margin-right: auto;
}
body {
max-width: 1000px;
margin-left: auto !important;
margin-right: auto !important;
}
div.tooltip-inner {
max-width: 25rem;
}
@@ -28,6 +22,10 @@ div.tooltip-inner {
.kaehmy-content {
padding-left: 0.5rem;
padding-right: 0.5rem;
max-width: 1000px;
width: 100%;
margin-left: auto;
margin-right: auto;
}
p {
+2 -5
View File
@@ -3,13 +3,9 @@
}
footer {
/* position: absolute; */
bottom: 0;
width: 100%;
height: 60px; /* Set the fixed height of the footer here */
/* line-height: 60px; /* Vertically center the text there */
margin-top: 2rem;
margin-bottom: 1rem;
margin: 1rem;
}
footer .container .col .nav .nav-item {
@@ -26,6 +22,7 @@ footer .container .col .nav .nav-item {
.lang-select {
width: 10rem;
margin-bottom: 1rem;
display: inline-block;
}
+18 -27
View File
@@ -1,37 +1,28 @@
.header-content {
.kaehmy-header {
background-color: #0c2938;
}
.header-content .logo {
.kaehmy-header-content {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: center;
}
.header-content .logo img {
display: block;
height: auto;
margin: auto;
}
.kaehmy-banner {
max-width: 1000px;
width: 100%;
margin-left: auto;
margin-right: auto;
}
@media screen and (min-width: 1000px) {
.kaehmy_header-content {
position: absolute;
left: 0;
top: 0;
background-color: #0c2938;
width: 100%;
}
.kaehmy_header {
margin-bottom: 331px;
}
}
.kaehmy-banner-image {
width: 100%;
max-height: 10rem;
max-width: 100%;
}
.heading {
display: flex;
place-content: center;
flex-direction: column;
text-align: center;
margin: 1rem;
}
+7 -3
View File
@@ -1,11 +1,15 @@
.kaehmy_navigation {
margin-bottom: 10px;
}
.navbar-border {
border-bottom: 2px solid #282b3b;
}
.navbar-light .navbar-nav .nav-link {
color: black;
}
.navbar {
max-width: 1000px;
width: 100%;
margin-left: auto;
margin-right: auto;
}
+1 -1
View File
@@ -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
-24
View File
@@ -1,24 +0,0 @@
{% load i18n %}
{% load static %}
{% load staticfiles %}
<footer style="text-align: center">
<div>
<form class="lang-form form" action="{% url 'set_language' %}" method="post">{% csrf_token %}
<span>
<input name="next" type="hidden" value="{{ redirect_to }}" />
<select onchange="this.form.submit()" class="lang-select form-control" name="language">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected="selected"{% endif %}>
{{ language.name_local }} ({{ language.code }})
</option>
{% endfor %}
</select>
</span>
</form>
<span>{% trans "Copyright Aalto-yliopiston Sähköinsinöörikilta ry" %} {% now 'Y' %}</span>
</div>
</footer>
-7
View File
@@ -1,7 +0,0 @@
{% load i18n %}
<div class="kaehmy_header-content">
<div class="kaehmy-banner logo">
<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>
+8 -8
View File
@@ -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:
+19 -22
View File
@@ -1,15 +1,12 @@
from django.db.models import Count
from django.shortcuts import render, redirect
from django.contrib.auth import login, logout, authenticate
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.contrib.auth.decorators import permission_required, login_required
from django.conf import settings
from django.http import HttpResponseRedirect
from django.contrib.auth.decorators import login_required
from django.template.loader import render_to_string
import logging
import requests
from dealer.git import git
from sikweb.settings import URL
from members.views.utils import *
@@ -56,7 +53,7 @@ def list_view(request, *args, **kwargs):
"filter_options": filter_options,
}
return render(request, "kaehmy:list.html", context)
return render(request, "kaehmy/list.html", context)
@ensure_csrf_cookie
@@ -68,20 +65,21 @@ def comment(request, *args, **kwargs):
if form.is_valid():
comment = form.save()
name = comment.name
url = f"https://{URL}/kaehmy"
to_email = comment.parent.email
subject = "Kaehmyysi tai kommenttiisi on vastattu!"
email_body = (
f"{name.capitalize()} on vastannut kaehmyhakemukseesi tai kommenttiisi kaehmypalvelussa.\r\n\r\n"
"Käy lukemassa viesti osoitteessa https://{URL}/kaehmy"
message = render_to_string(
"kaehmy/email_comment.html", {"name": name, "url": url}
)
send_email(to=to_email, subject=subject, body=email_body)
send_email(to=to_email, subject=subject, body=message, html=True)
logging.debug(f"Sent kaehmy comment email to recipient <{to_email}>")
return redirect("/kaehmy")
else:
context = {"error": form.errors}
return render(request, "kaehmy:error.html", context)
return render(request, "kaehmy/error.html", context)
@require_http_methods(["GET"])
@@ -106,14 +104,14 @@ def statistics_view(request, *args, **kwargs):
"application_count": len(applications),
"role_list": role_list,
}
return render(request, "kaehmy:statistics.html", context)
return render(request, "kaehmy/statistics.html", context)
@require_http_methods(["GET"])
def view(request, *args, **kwargs):
"""Render Kaehmy form page."""
form = ApplicationForm()
return render(request, "kaehmy:kaehmy.html", {"form": form})
return render(request, "kaehmy/kaehmy.html", {"form": form})
@ensure_csrf_cookie
@@ -125,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)
@@ -133,22 +132,20 @@ def submit(request, *args, **kwargs):
url = f"https://{URL}/kaehmy"
name = form.cleaned_data.get("name", "Anonymous")
email_body = (
f"Moikka {name}!\r\n\r\nHienoa, että kilta kiinnostaa! Kaehmysi on vastaanotettu.\r\n"
"Mahdollisista kommenteista tulee ilmoitus sähköpostitse.\r\n\r\n"
"Käy katsomassa kaehmytilanne osoitteessa {url}"
)
to_email = form.cleaned_data.get("email", "")
subject = "Arwokas kirjattu kirje mahdolliselle tulewalle kiltahenkilölle"
message = render_to_string(
"kaehmy/email_kaehmy.html", {"name": name, "url": url}
)
send_email(to_email, subject, email_body)
send_email(to=to_email, subject=subject, body=message, html=True)
logging.debug(f"Sent kaehmy email to recipient <{to_email}>")
processHooks(message=f"Uusi New kaehmy! {name} -> {url}", eventType="kaehmy")
else:
context = {"error": form.errors}
return render(request, "kaehmy:error.html", context)
return render(request, "kaehmy/error.html", context)
return HttpResponseRedirect("/kaehmy")
@@ -175,4 +172,4 @@ def export_view(request, *args, **kwargs):
"non_board_table": make_table(non_board),
"board_table": make_table(board),
}
return render(request, "kaehmy:export.html", context)
return render(request, "kaehmy/export.html", context)
Binary file not shown.
File diff suppressed because it is too large Load Diff
Binary file not shown.
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -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
@@ -0,0 +1,18 @@
# Generated by Django 3.2.14 on 2022-08-01 19:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("members", "0019_auto_20171029_1143"),
]
operations = [
migrations.AlterField(
model_name="payment",
name="id",
field=models.AutoField(primary_key=True, serialize=False),
),
]
@@ -0,0 +1,23 @@
# Generated by Django 3.2.14 on 2022-08-01 19:15
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("members", "0020_alter_payment_id"),
]
operations = [
migrations.AlterField(
model_name="member",
name="id",
field=models.AutoField(primary_key=True, serialize=False),
),
migrations.AlterField(
model_name="request",
name="id",
field=models.AutoField(primary_key=True, serialize=False),
),
]
+3 -1
View File
@@ -2,13 +2,14 @@
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
class BaseMember(models.Model):
"""Abstract base model for member."""
id = models.AutoField(primary_key=True)
first_name = models.CharField(_("First name"), max_length=127)
last_name = models.CharField(_("Last name"), max_length=127)
email = models.EmailField(_("Email"), unique=True)
@@ -60,6 +61,7 @@ class Payment(models.Model):
class Meta:
permissions = (("read_payment", "Can see payment in list"),)
id = models.AutoField(primary_key=True)
date = models.DateTimeField(_("Date"), default=timezone.now)
source = models.CharField(
_("Source"),
+1 -1
View File
@@ -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
@@ -1,11 +0,0 @@
{% 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
+13 -5
View File
@@ -5,6 +5,7 @@ from unittest import skip
from django.contrib.auth.models import User
from members.models import Member, Payment, Request
from rest_framework.authtoken.models import Token
from datetime import timezone
import logging
@@ -108,8 +109,11 @@ class MemberRegisterTestCase(TestCase):
content = resp.content
arrays = pyexcel.get_array(file_content=content, file_type="xlsx")
created = Payment.objects.get(member__email="tidus@tester.fi").date.strftime(
"%Y-%m-%d %H:%M:%S"
created = (
Payment.objects.get(member__email="tidus@tester.fi")
.date.replace(tzinfo=timezone.utc)
.astimezone(tz=None)
.strftime("%Y-%m-%d %H:%M:%S")
)
tidus_array = ["Tidus Tester", created, "AYY"]
self.assertIn(tidus_array, arrays)
@@ -122,9 +126,13 @@ class MemberRegisterTestCase(TestCase):
content = resp.content
arrays = pyexcel.get_array(file_content=content, file_type="xlsx")
submitted = Request.objects.get(
email="liisa.mattila@pylly.com"
).submitted.strftime("%Y-%m-%d %H:%M:%S")
submitted = (
Request.objects.get(email="liisa.mattila@pylly.com")
.submitted.replace(tzinfo=timezone.utc)
.astimezone(tz=None)
.strftime("%Y-%m-%d %H:%M:%S")
)
liisa_array = [
"Liisa",
"Mattila",
+33 -33
View File
@@ -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
View File
@@ -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 _
+15 -9
View File
@@ -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
@@ -12,6 +12,7 @@ import logging
import html
from webapp.utils import send_email
from webapp.utils import add_to_mailinglist
from members.views.utils import *
from members.tables import RequestTable
@@ -41,7 +42,7 @@ def application_list(request, *args, **kwargs):
"application_count": application_count,
"notification": request.GET.get("notification", None),
}
return render(request, "application_list.html", context)
return render(request, "members/application_list.html", context)
@ensure_csrf_cookie
@@ -57,7 +58,9 @@ def application_edit(request, *args, **kwargs):
application = Request.objects.get(id=i)
form = ApplicationForm(instance=application)
return render(
request, "application_edit.html", {"application_id": i, "form": form}
request,
"members/application_edit.html",
{"application_id": i, "form": form},
)
@@ -86,6 +89,9 @@ def application_accept(request, *args, **kwargs):
).format(application.email),
)
if application.jas:
add_to_mailinglist(application.email)
member = application.to_member()
member.save()
application.delete()
@@ -101,10 +107,10 @@ def application_accept(request, *args, **kwargs):
subject = _("Jäsenhakemuksesi Sähköinsinöörikiltaan on hyväksytty!")
message = render_to_string(
"members:email_application_accept.html",
"members/email_application_accept.html",
{"first_name": application.first_name},
)
send_email(member.email, subject, message)
send_email(member.email, subject, message, True)
return HttpResponseRedirect(
"/members/list?notification={}".format(html.escape(notification))
@@ -158,7 +164,7 @@ def application_delete_confirm(request, *args, **kwargs):
form = ApplicationForm(instance=application)
return render(
request,
"application_delete_confirm.html",
"members/application_delete_confirm.html",
{"application_id": i, "form": form},
)
@@ -167,7 +173,7 @@ def application_delete_confirm(request, *args, **kwargs):
def application_form(request, *args, **kwargs):
"""Render member application form."""
form = ApplicationForm()
return render(request, "application_index.html", {"form": form})
return render(request, "members/application_index.html", {"form": form})
@ensure_csrf_cookie
@@ -186,7 +192,7 @@ def application_submit(request, *args, **kwargs):
)
message = render_to_string(
"members:email_application_submit.html",
"members/email_application_submit.html",
{
"application": application,
"ayy": _("Kyllä") if application.AYY else _("Ei"),
@@ -195,6 +201,6 @@ def application_submit(request, *args, **kwargs):
)
send_email(email, subject, message)
finally:
return render(request, "application_success.html", {})
return render(request, "members/application_success.html", {})
else:
return error_view(request, form.errors)
+11 -7
View File
@@ -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
@@ -70,7 +70,7 @@ def member_list(request, *args, **kwargs):
"paid_count": len(queryset.filter(last_paid__gte=filter_date)),
"notification": request.GET.get("notification", None),
}
return render(request, "member_list.html", context)
return render(request, "members/member_list.html", context)
@ensure_csrf_cookie
@@ -80,7 +80,7 @@ def member_list(request, *args, **kwargs):
def member_add(request, *args, **kwargs):
"""Render add member page."""
form = MemberForm()
return render(request, "member_add.html", {"form": form})
return render(request, "members/member_add.html", {"form": form})
@ensure_csrf_cookie
@@ -96,7 +96,9 @@ def member_delete_confirm(request, *args, **kwargs):
member = Member.objects.get(id=i)
form = MemberForm(instance=member)
return render(
request, "member_delete_confirm.html", {"member_id": i, "form": form}
request,
"members/member_delete_confirm.html",
{"member_id": i, "form": form},
)
@@ -106,7 +108,7 @@ def member_delete_confirm(request, *args, **kwargs):
@permission_required("members.add_member", raise_exception=True)
def member_add_many(request, *args, **kwargs):
"""Render add multiple members page."""
return render(request, "member_add_many.html", {})
return render(request, "members/member_add_many.html", {})
@ensure_csrf_cookie
@@ -233,7 +235,9 @@ def member_edit(request, *args, **kwargs):
else:
member = Member.objects.get(id=i)
form = MemberForm(instance=member)
return render(request, "member_edit.html", {"member_id": i, "form": form})
return render(
request, "members/member_edit.html", {"member_id": i, "form": form}
)
@method_decorator(login_required(login_url="/admin/login"), name="dispatch")
@@ -245,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):
+9 -5
View File
@@ -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
@@ -43,7 +43,7 @@ def payment_list(request, *args, **kwargs):
"payment_count": len(payments),
"notification": request.GET.get("notification", None),
}
return render(request, "payment_list.html", context)
return render(request, "members/payment_list.html", context)
@ensure_csrf_cookie
@@ -53,7 +53,7 @@ def payment_list(request, *args, **kwargs):
def payment_add(request, *args, **kwargs):
"""Render add payment form."""
form = PaymentForm()
return render(request, "payment_add.html", {"form": form})
return render(request, "members/payment_add.html", {"form": form})
@ensure_csrf_cookie
@@ -92,7 +92,9 @@ def payment_edit(request, *args, **kwargs):
else:
payment = Payment.objects.get(id=i)
form = PaymentForm(instance=payment)
return render(request, "payment_edit.html", {"payment_id": i, "form": form})
return render(
request, "members/payment_edit.html", {"payment_id": i, "form": form}
)
@ensure_csrf_cookie
@@ -108,7 +110,9 @@ def payment_delete_confirm(request, *args, **kwargs):
payment = Payment.objects.get(id=i)
form = PaymentForm(instance=payment)
return render(
request, "payment_delete_confirm.html", {"payment_id": i, "form": form}
request,
"members/payment_delete_confirm.html",
{"payment_id": i, "form": form},
)
+5 -5
View File
@@ -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
@@ -46,7 +46,7 @@ class MemberDetail(generics.RetrieveAPIView):
def error_view(request, message, status=400):
return render(request, "error.html", {"error": message}, status=400)
return render(request, "members/error.html", {"error": message}, status=400)
def validate_recaptcha(response):
@@ -100,7 +100,7 @@ def convert_table_to_html(table, request):
@permission_required("members.change_member", raise_exception=True)
def settings_page(request, *args, **kwargs):
"""Render member app settings page."""
return render(request, "settings.html", {})
return render(request, "members/settings.html", {})
@ensure_csrf_cookie
@@ -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"},
)
@@ -155,7 +155,7 @@ def import_csv(request, *args, **kwargs):
request.session["models"] = result
request.session["payment_source"] = payment_source
context = {"members": member_table_html, "payments": payment_table_html}
return render(request, "member_add_many_confirm.html", context)
return render(request, "members/member_add_many_confirm.html", context)
def make_excel_response(Resource):
+1 -1
View File
@@ -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
@@ -0,0 +1,18 @@
# Generated by Django 3.2.14 on 2022-08-01 19:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("ohlhafv", "0002_remove_ohlhafvchallenge_challenger_email"),
]
operations = [
migrations.AlterField(
model_name="ohlhafvchallenge",
name="id",
field=models.AutoField(primary_key=True, serialize=False),
),
]
+2 -1
View File
@@ -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
@@ -29,6 +29,7 @@ class OhlhafvChallenge(models.Model):
("Team", _("Team Challenge (1 x 0.33 L, 2 x 0.5 L, 1 x 1.0 L)")),
)
id = models.AutoField(primary_key=True)
challenger = models.CharField(_("Challenger"), max_length=255)
victim = models.CharField(_("Victim"), max_length=255)
victim_email = models.EmailField(_("Victim email"))
+1
View File
@@ -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: 234 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 MiB

+1 -1
View File
@@ -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
-25
View File
@@ -1,25 +0,0 @@
{% load i18n %}
{% load static %}
{% load staticfiles %}
<link rel="stylesheet" href="{% static "ohlhafv/css/footer.css" %}">
<footer style="text-align: center">
<div>
<form class="lang-form form" action="{% url 'set_language' %}" method="post">{% csrf_token %}
<span>
<input name="next" type="hidden" value="{{ redirect_to }}" />
<select onchange="this.form.submit()" class="lang-select form-control" name="language">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected="selected"{% endif %}>
{{ language.name_local }} ({{ language.code }})
</option>
{% endfor %}
</select>
</span>
</form>
<span>{% trans "Copyright Aalto-yliopiston Sähköinsinöörikilta ry" %} {% now 'Y' %}</span>
</div>
</footer>
+5 -5
View File
@@ -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:
+5 -5
View File
@@ -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
@@ -18,7 +18,7 @@ from webapp.models import processHooks
def ohlhafv_view(request, *args, **kwargs):
"""Render Ohlhafv form page."""
form = OhlhafvForm()
return render(request, "ohlhafv:new.html", {"form": form})
return render(request, "ohlhafv/new.html", {"form": form})
@ensure_csrf_cookie
@@ -32,7 +32,7 @@ def ohlhafv_submit(request, *args, **kwargs):
url = f"https://{URL}/ohlhafv/list"
email_body = render_to_string(
"ohlhafv:email.html",
"ohlhafv/email.html",
{
"challenge": challenge,
"url": url,
@@ -46,7 +46,7 @@ def ohlhafv_submit(request, *args, **kwargs):
try:
webhook_message = render_to_string(
"ohlhafv:tgmsg.tpl", {"challenge": challenge, "url": url}
"ohlhafv/tgmsg.tpl", {"challenge": challenge, "url": url}
)
processHooks(message=webhook_message, eventType="ohlhafv")
except Exception:
@@ -67,4 +67,4 @@ def ohlhafv_list(request, *args, **kwargs):
"challenges": challenges,
"challenge_count": len(challenges),
}
return render(request, "ohlhafv:list.html", context)
return render(request, "ohlhafv/list.html", context)
+1 -1
View File
@@ -6,7 +6,7 @@
"lint": "run-p lint:js lint:md lint:py",
"lint:js": "eslint .",
"lint:md": "remark .",
"lint:py": "black --diff .",
"lint:py": "black --diff --check .",
"lint:py:fix": "black .",
"lint:py-type": "pyright",
"prepare": "husky install"
Generated
+1181 -765
View File
File diff suppressed because it is too large Load Diff
+19 -4
View File
@@ -4,15 +4,30 @@
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 "$DB_PASSWD_FILE"; then
export DB_PASSWD=$(cat $DB_PASSWD_FILE)
fi
if test -f "$G_PRIVATE_KEY_ID_FILE"; then
export G_PRIVATE_KEY_ID=$(cat $G_PRIVATE_KEY_ID_FILE)
fi
if test -f "$G_PRIVATE_KEY_FILE"; then
export G_PRIVATE_KEY="$(cat $G_PRIVATE_KEY_FILE)"
fi
if test -f "$G_CLIENT_EMAIL_FILE"; then
export G_CLIENT_EMAIL=$(cat $G_CLIENT_EMAIL_FILE)
fi
if test -f "$G_CLIENT_ID_FILE"; then
export G_CLIENT_ID=$(cat $G_CLIENT_ID_FILE)
fi
if test -f "$G_CLIENT_URL_FILE"; then
export G_CLIENT_URL=$(cat $G_CLIENT_URL_FILE)
fi
if test -f "$GROUP_KEY_FILE"; then
export GROUP_KEY=$(cat $GROUP_KEY_FILE)
fi
# Collect static files
echo "Collect static files"
@@ -24,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
+24 -24
View File
@@ -7,43 +7,43 @@ authors = ["Aarni Halinen aarni.halinen@sahkoinsinoorikilta.fi"]
[tool.poetry.dependencies]
python = "^3.9"
decorator = "^4.0.9"
Django = "^2.2.19"
requests = "^2.11.1"
django-cors-headers = "^3.7.0"
Django = "^4.1"
requests = "^2.28.1"
django-cors-headers = "^3.13.0"
djangorestframework = "^3.12.4"
djangorestframework-jwt = "^1.11.0"
django-nose = "^1.4.5"
psycopg2-binary = "2.8.6"
django-bootstrap3 = "^11.1.0"
django-tables2 = "^1.6.1"
dealer = "^2.0.5"
django-modeltranslation = "^0.13b1"
django-auditlog = "^0.4.5"
django-phonenumber-field = {version = "^4.0.0", extras = ["phonenumbers"]}
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"
django-suit = "^0.2.26"
pyexcel = "^0.5.14"
pyexcel-xlsx = "^0.5.8"
django-import-export = "^0.7.0"
pyexcel = "^0.7.0"
pyexcel-xlsx = "^0.6.0"
django-import-export = "^2.8.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"
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 = "^8.4.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"
pyexcel-io = "^0.6.6"
[tool.poetry.dev-dependencies]
coverage = "^5.5"
nose-exclude = "^0.5.0"
safety = "^1.10.3"
black = "^21.12b0"
coverage = "^6.4.2"
safety = "^2.1.1"
black = "^22.6.0"
[build-system]
requires = ["poetry-core>=1.0.0"]
+2 -2
View File
@@ -3,8 +3,8 @@ CREATE USER sik WITH PASSWORD 'password123';
ALTER ROLE sik SET client_encoding TO 'utf8';
ALTER ROLE sik SET default_transaction_isolation TO 'read committed';
ALTER ROLE sik SET timezone TO 'UTC';
CREATE DATABASE sik
ENCODING 'UTF8'
CREATE DATABASE sik
ENCODING 'UTF8'
OWNER sik;
GRANT ALL PRIVILEGES ON DATABASE sik TO sik;
ALTER USER sik CREATEDB;
+24 -93
View File
@@ -2,19 +2,31 @@ 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__)))
# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/1.9/howto/deployment/checklist/
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.9/howto/static-files/
STATIC_URL = "static/"
STATIC_ROOT = os.path.join(BASE_DIR, "collected_static")
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
]
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_URL = "/media/"
# Login paths
LOGIN_URL = "/login/"
LOGIN_REDIRECT_URL = "/admin"
# Might need to be changed to JSON serializer
# https://docs.djangoproject.com/en/4.0/topics/http/sessions/#django.contrib.sessions.serializers.JSONSerializer
SESSION_SERIALIZER = "django.contrib.sessions.serializers.PickleSerializer"
# Logger level
# Logging
LOGGERLEVEL = logging.DEBUG
LOGPATH = os.path.join(BASE_DIR, "logs", "debug.log")
@@ -67,10 +79,15 @@ LOGGING = {
# Application definition
IMPORT_EXPORT_USE_TRANSACTIONS = True
# Could be replaced with CORS_ALLOWED_ORIGINS list.
# See (check correct package version in the link) https://github.com/adamchainz/django-cors-headers/tree/3.7.0#configuration
CORS_ALLOW_ALL_ORIGINS = True
ROOT_URLCONF = "sikweb.urls"
WSGI_APPLICATION = "sikweb.wsgi.application"
INSTALLED_APPS = [
"modeltranslation", # has to be before admin for translation admin to work
"suit",
"dal",
"dal_select2",
"django.contrib.admin",
@@ -87,8 +104,7 @@ INSTALLED_APPS = [
"kaehmy",
"ohlhafv",
"rest_framework",
"rest_framework_jwt",
"django_nose",
"rest_framework_simplejwt",
"bootstrap3",
"django_tables2",
"auditlog",
@@ -97,18 +113,6 @@ INSTALLED_APPS = [
"django_filters",
]
IMPORT_EXPORT_USE_TRANSACTIONS = True
TEST_RUNNER = "django_nose.NoseTestSuiteRunner"
NOSE_ARGS = [
"--with-coverage",
"--cover-package=webapp,members,infoscreen",
"--exclude-dir={}".format(os.path.join(BASE_DIR, "members", "migrations")),
"--exclude-dir={}".format(os.path.join(BASE_DIR, "infoscreen", "migrations")),
"--exclude-dir={}".format(os.path.join(BASE_DIR, "webapp", "migrations")),
]
MIDDLEWARE = [
"sikweb.middleware.ForceDefaultLanguageMiddleware",
"django.middleware.security.SecurityMiddleware",
@@ -124,17 +128,12 @@ MIDDLEWARE = [
"auditlog.middleware.AuditlogMiddleware",
]
CORS_ORIGIN_ALLOW_ALL = True
ROOT_URLCONF = "sikweb.urls"
TEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": ["templates"],
"OPTIONS": {
"loaders": [
"app_namespace.Loader",
"django.template.loaders.filesystem.Loader",
"django.template.loaders.app_directories.Loader",
],
@@ -145,17 +144,14 @@ TEMPLATES = [
"django.contrib.auth.context_processors.auth",
"django.contrib.messages.context_processors.messages",
"django.template.context_processors.static",
"dealer.contrib.django.context_processor",
],
},
},
]
WSGI_APPLICATION = "sikweb.wsgi.application"
# Password validation
# https://docs.djangoproject.com/en/1.9/ref/settings/#auth-password-validators
AUTH_PASSWORD_VALIDATORS = [
{
"NAME": "django.contrib.auth.password_validation."
@@ -179,88 +175,23 @@ REST_FRAMEWORK = {
"rest_framework.permissions.IsAdminUser",
),
"DEFAULT_AUTHENTICATION_CLASSES": (
"rest_framework_jwt.authentication.JSONWebTokenAuthentication",
"rest_framework_simplejwt.authentication.JWTAuthentication",
),
# '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": 1000,
"DEFAULT_FILTER_BACKENDS": ("django_filters.rest_framework.DjangoFilterBackend",),
}
# Email settings (tested working with gmail)
# EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# EMAIL_USE_TLS = True
# EMAIL_HOST = 'smtp.gmail.com'
# EMAIL_PORT = 587
# Internationalization
# https://docs.djangoproject.com/en/1.9/topics/i18n/
LANGUAGES = (
("fi", _("Finnish")),
("en", _("English")),
)
LANGUAGE_CODE = "fi"
LOCALE_PATHS = (os.path.join(BASE_DIR, "locale"),)
TIME_ZONE = "Europe/Helsinki"
USE_I18N = True
USE_L10N = True
USE_TZ = True
# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/1.9/howto/static-files/
STATICFILES_FINDERS = (
"django.contrib.staticfiles.finders.AppDirectoriesFinder",
"django.contrib.staticfiles.finders.FileSystemFinder",
)
STATIC_URL = "/static/"
STATIC_ROOT = os.path.join(BASE_DIR, "collected_static")
STATICFILES_DIRS = (os.path.join(BASE_DIR, "static"),)
MEDIA_ROOT = os.path.join(BASE_DIR, "media")
MEDIA_URL = "/media/"
LOGIN_URL = "/login/"
LOGIN_REDIRECT_URL = "/admin"
SUIT_CONFIG = {
# header
"ADMIN_NAME": "SIK Admin",
# 'HEADER_DATE_FORMAT': 'l, j. F Y',
# 'HEADER_TIME_FORMAT': 'H:i',
# forms
# 'SHOW_REQUIRED_ASTERISK': True, # Default True
# 'CONFIRM_UNSAVED_CHANGES': True, # Default True
# menu
# 'SEARCH_URL': '/admin/auth/user/',
# 'MENU_ICONS': {
# 'sites': 'icon-leaf',
# 'auth': 'icon-lock',
# },
# 'MENU_OPEN_FIRST_CHILD': True, # Default True
# 'MENU_EXCLUDE': ('auth.group',),
# 'MENU': (
# 'sites',
# {'app': 'auth', 'icon':'icon-lock', 'models': ('user', 'group')},
# {'label': 'Settings', 'icon':'icon-cog', 'models': ('auth.user', 'auth.group')},
# {'label': 'Support', 'icon':'icon-question-sign', 'url': '/support/'},
# ),
# misc
# 'LIST_PER_PAGE': 15
}
JWT_AUTH = {"JWT_EXPIRATION_DELTA": datetime.timedelta(days=7)}
+30
View File
@@ -0,0 +1,30 @@
# contents of yourapp/migrations/custom_operations.py
from django.db.migrations.operations.models import ModelOperation
class AlterModelBases(ModelOperation):
reduce_to_sql = False
reversible = True
def __init__(self, name, bases):
self.bases = bases
super().__init__(name)
def state_forwards(self, app_label, state):
"""
Overwrite a models base classes with a custom list of
bases instead, then force Django to reload the model
with this (probably completely) different class hierarchy.
"""
state.models[app_label, self.name_lower].bases = self.bases
state.reload_model(app_label, self.name_lower)
def database_forwards(self, app_label, schema_editor, from_state, to_state):
pass
def database_backwards(self, app_label, schema_editor, from_state, to_state):
pass
def describe(self):
return "Update %s bases to %s" % (self.name, self.bases)
+66 -20
View File
@@ -10,23 +10,17 @@ For the full list of settings and their values, see
https://docs.djangoproject.com/en/1.9/ref/settings/
"""
from dotenv import load_dotenv
import sentry_sdk
from sentry_sdk.integrations.django import DjangoIntegration
from sikweb.base import *
from datetime import timedelta
import json
load_dotenv() # loads the configs from .env
SENTRY_DSN = os.getenv("SENTRY_DSN", "")
DEPLOY_ENV = os.getenv("DEPLOY_ENV", "production")
# Setup sentry
sentry_sdk.init(
dsn=SENTRY_DSN,
environment=DEPLOY_ENV,
integrations=[DjangoIntegration()],
# If you wish to associate users to errors (assuming you are using
# django.contrib.auth) you may enable sending PII data.
send_default_pii=True,
)
# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = os.getenv("DEBUG", False) == "True"
@@ -44,6 +38,19 @@ SECRET_KEY = os.getenv(
"SECRET_KEY", "7p$85^4ibb^p4-=vs44b7!y0e-zemugze18@a#30&71=a8)dp("
)
# Sentry
SENTRY_DSN = os.getenv("SENTRY_DSN", "")
sentry_sdk.init(
dsn=SENTRY_DSN,
environment=DEPLOY_ENV,
integrations=[DjangoIntegration()],
# If you wish to associate users to errors (assuming you are using
# django.contrib.auth) you may enable sending PII data.
send_default_pii=True,
)
# ReCaptcha
# http://www.yaconiello.com/blog/integrating-google-recaptcha-to-django/
GOOGLE_RECAPTCHA_SITE_KEY = os.getenv("GOOGLE_RECAPTCHA_SITE_KEY", "YOUR-PUBLIC-KEY")
@@ -51,24 +58,19 @@ GOOGLE_RECAPTCHA_SECRET_KEY = os.getenv(
"GOOGLE_RECAPTCHA_SECRET_KEY", "YOUR-PRIVATE-KEY"
)
# Email settings (more settings in base.py)
# Email settings (Sendgrid)
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
## Database connection
DB_OPTIONS = {"sslmode": "require"} if os.getenv("DB_SSL", False) == "True" else {}
DATABASES = {
"default": {
"ENGINE": "django.db.backends.postgresql_psycopg2",
"ENGINE": "django.db.backends.postgresql",
"NAME": os.getenv("DB_NAME", "postgres"),
"USER": os.getenv("DB_USER", "postgres"),
"PASSWORD": os.getenv("DB_PASSWD", "postgres"),
@@ -77,3 +79,47 @@ DATABASES = {
"OPTIONS": DB_OPTIONS,
}
}
# Google api settings
GROUP_KEY = os.getenv("GROUP_KEY", "")
GOOGLE_CREDS = {
"type": "service_account",
"project_id": "web2-backend",
"private_key_id": os.getenv("G_PRIVATE_KEY_ID", ""),
"private_key": os.getenv("G_PRIVATE_KEY", ""),
"client_email": os.getenv("G_CLIENT_EMAIL", ""),
"client_id": os.getenv("G_CLIENT_ID", ""),
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": os.getenv("G_CLIENT_URL", ""),
}
# JWT authentication
SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=5),
"REFRESH_TOKEN_LIFETIME": timedelta(days=1),
"ROTATE_REFRESH_TOKENS": False,
"BLACKLIST_AFTER_ROTATION": False,
"UPDATE_LAST_LOGIN": False,
"ALGORITHM": "HS256",
"SIGNING_KEY": SECRET_KEY,
"VERIFYING_KEY": None,
"AUDIENCE": None,
"ISSUER": None,
"JWK_URL": None,
"LEEWAY": 0,
"AUTH_HEADER_TYPES": ("Bearer",),
"AUTH_HEADER_NAME": "HTTP_AUTHORIZATION",
"USER_ID_FIELD": "id",
"USER_ID_CLAIM": "user_id",
"USER_AUTHENTICATION_RULE": "rest_framework_simplejwt.authentication.default_user_authentication_rule",
"AUTH_TOKEN_CLASSES": ("rest_framework_simplejwt.tokens.AccessToken",),
"TOKEN_TYPE_CLAIM": "token_type",
"TOKEN_USER_CLASS": "rest_framework_simplejwt.models.TokenUser",
"JTI_CLAIM": "jti",
"SLIDING_TOKEN_REFRESH_EXP_CLAIM": "refresh_exp",
"SLIDING_TOKEN_LIFETIME": timedelta(minutes=5),
"SLIDING_TOKEN_REFRESH_LIFETIME": timedelta(days=1),
}
+13 -28
View File
@@ -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)
+24
View File
@@ -29,15 +29,39 @@ services:
- FRONTEND_URL=dev.sahkoinsinoorikilta.fi
- DEBUG=True
- EMAIL_API_KEY_FILE=/run/secrets/DJANGO_EMAIL_API_KEY
- G_PRIVATE_KEY_ID_FILE=/run/secrets/BACKEND_G_PRIVATE_KEY_ID
- G_PRIVATE_KEY_FILE=/run/secrets/BACKEND_G_PRIVATE_KEY
- G_CLIENT_EMAIL_FILE=/run/secrets/BACKEND_G_CLIENT_EMAIL
- G_CLIENT_ID_FILE=/run/secrets/BACKEND_G_CLIENT_ID
- G_CLIENT_URL_FILE=/run/secrets/BACKEND_G_CLIENT_URL
- GROUP_KEY_FILE=/run/secrets/BACKEND_GROUP_KEY
- DB_HOST=db
- DB_PORT=5432
secrets:
- DJANGO_EMAIL_API_KEY
- BACKEND_G_PRIVATE_KEY_ID
- BACKEND_G_PRIVATE_KEY
- BACKEND_G_CLIENT_EMAIL
- BACKEND_G_CLIENT_ID
- BACKEND_G_CLIENT_URL
- BACKEND_GROUP_KEY
secrets:
DJANGO_EMAIL_API_KEY:
external: true
BACKEND_G_PRIVATE_KEY_ID:
external: true
BACKEND_G_PRIVATE_KEY:
external: true
BACKEND_G_CLIENT_EMAIL:
external: true
BACKEND_G_CLIENT_ID:
external: true
BACKEND_G_CLIENT_URL:
external: true
BACKEND_GROUP_KEY:
external: true
volumes:
dbdata:
+25 -4
View File
@@ -32,21 +32,42 @@ services:
- DB_PORT=5432
- DB_SSL=True
- SECRET_KEY_FILE=/run/secrets/BACKEND_SECRET_KEY
- TG_BOT_TOKEN_FILE=/run/secrets/BACKEND_TG_BOT_TOKEN
- DB_PASSWD_FILE=/run/secrets/BACKEND_DB_PASSWD
- EMAIL_API_KEY_FILE=/run/secrets/BACKEND_EMAIL_API_KEY
- G_PRIVATE_KEY_ID_FILE=/run/secrets/BACKEND_G_PRIVATE_KEY_ID
- G_PRIVATE_KEY_FILE=/run/secrets/BACKEND_G_PRIVATE_KEY
- G_CLIENT_EMAIL_FILE=/run/secrets/BACKEND_G_CLIENT_EMAIL
- G_CLIENT_ID_FILE=/run/secrets/BACKEND_G_CLIENT_ID
- G_CLIENT_URL_FILE=/run/secrets/BACKEND_G_CLIENT_URL
- GROUP_KEY_FILE=/run/secrets/BACKEND_GROUP_KEY
secrets:
- BACKEND_SECRET_KEY
- BACKEND_TG_BOT_TOKEN
- BACKEND_DB_PASSWD
- BACKEND_EMAIL_API_KEY
- BACKEND_G_PRIVATE_KEY_ID
- BACKEND_G_PRIVATE_KEY
- BACKEND_G_CLIENT_EMAIL
- BACKEND_G_CLIENT_ID
- BACKEND_G_CLIENT_URL
- BACKEND_GROUP_KEY
secrets:
BACKEND_SECRET_KEY:
external: true
BACKEND_TG_BOT_TOKEN:
external: true
BACKEND_DB_PASSWD:
external: true
BACKEND_EMAIL_API_KEY:
external: true
BACKEND_G_PRIVATE_KEY_ID:
external: true
BACKEND_G_PRIVATE_KEY:
external: true
BACKEND_G_CLIENT_EMAIL:
external: true
BACKEND_G_CLIENT_ID:
external: true
BACKEND_G_CLIENT_URL:
external: true
BACKEND_GROUP_KEY:
external: true
@@ -3475,19 +3475,19 @@
}
while( (node = node.parentNode) && (node !== document.body) );
},
disableMouseover: false,
mouseover: function (evt){
if (!flash.disableMouseover) {
var target = api.event.fix(evt).target;
if( /input/i.test(target.nodeName) && target.type == 'file' && !target.disabled ){
var
state = target.getAttribute(_attr)
, wrapper = flash.getWrapper(target)
;
if( api.multiFlash ){
// check state:
// i — published
@@ -3500,14 +3500,14 @@
else if( state != 'p' ){
// set "init" state
target.setAttribute(_attr, 'i');
var dummy = document.createElement('div');
if( !wrapper ){
api.log('[err] FlashAPI.mouseover: js-fileapi-wrapper not found');
return;
}
_css(dummy, {
top: 0
, left: 0
@@ -3516,21 +3516,21 @@
, zIndex: 1e6+'' // set max zIndex
, position: 'absolute'
});
wrapper.appendChild(dummy);
flash.publish(dummy, api.uid());
// set "publish" state
target.setAttribute(_attr, 'p');
}
return true;
}
else if( wrapper ){
// Use one flash element
var box = _getDimensions(wrapper);
_css(flash.getEl(), box);
// Set current input
flash.curInp = target;
}
@@ -3543,7 +3543,7 @@
onEvent: function (evt){
var type = evt.type;
if( type == 'ready' ){
try {
// set "ready" state
@@ -3632,9 +3632,9 @@
_each(files, function (file){
api.checkFileObj(file);
});
_files[uid] = files;
if( document.createEvent ){
event = document.createEvent('Event');
event.files = files;
@@ -3664,7 +3664,7 @@
this.cmdFn(id, name, data, last);
}
},
cmdFn: function(id, name, data, last) {
try {
api.log('(js -> flash).'+name+':', data);
@@ -3727,7 +3727,7 @@
callback(evt);
});
},
getFiles: function (input, filter, callback){
if( callback ){
api.filterFiles(api.getFiles(input), filter, callback);
@@ -4039,7 +4039,7 @@
}
try { el.style[key] = val; } catch (e) {}
}
}
}
@@ -4161,7 +4161,7 @@
, body = document.body
, docEl = (el && el.ownerDocument).documentElement
;
function getOffset(obj) {
var left, top;
left = top = 0;
@@ -4176,7 +4176,7 @@
top : top
};
};
return {
top: getOffset(el).top
, left: getOffset(el).left
-15
View File
@@ -1,15 +0,0 @@
<!DOCTYPE html>
{% load static %}
<html>
<head>
<link rel="shortcut icon" type="image/x-icon" href="/static/img/favicon.png"/>
<link rel="stylesheet" href="{% static "css/about.css" %}">
</head>
<body>
<h1>SIKWEB 2.0</h1>
<p>{{ commit }}</p>
<p>{{ date }}</p>
<p>{{ tag }}</p>
</body>
</html>
-75
View File
@@ -1,75 +0,0 @@
{% extends "admin/base.html" %}
{% load admin_static %}
{% load i18n %}
{# Additional <head> content here, some extra meta tags or favicon #}
{% block extrahead %}
<link rel="shortcut icon" type="image/x-icon" href="/static/img/favicon.png"/>
{% endblock %}
{# Additional CSS includes #}
{% block extrastyle %}
<link rel="stylesheet" type="text/css" href="{% static 'css/sikadmin.css' %}" media="all">
{% endblock %}
{# Additional JS files in footer, right before </body> #}
{#{% block extrajs %}#}
{# <script type="text/javascript" src="{% static 'js/my_project.js' %}"></script>#}
{#{% endblock %}#}
{# Footer links (left side) #}
{#{% block footer_links %}#}
{# <a href="/docs/" class="icon"><i class="icon-question-sign"></i>Documentation</a>#}
{#{% endblock %}#}
{# Additional header content like notifications or language switcher #}
{% block header_content %}
{{ block.super }}
<div class="header-content">
<form action="{% url 'set_language' %}" method="post">{% csrf_token %}
<input name="next" type="hidden" value="{{ redirect_to }}" />
<select name="language" style="width: auto;">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected="selected"{% endif %}>
{{ language.name_local }} ({{ language.code }})
</option>
{% endfor %}
</select>
<input class="btn btn-high" type="submit" value="{% trans 'Go' %}" style="vertical-align: top;"/>
</form>
<!-- First icon column -->
<!--
<div class="header-column icon">
<i class="icon-home"></i><br>
<i class="icon-cog"></i>
</div>
<div class="header-column" style="margin-right: 20px">
<a href="/" class="grey">Front-end</a><br>
<a href="" class="grey">One more link</a>
</div>
Second icon column
<div class="header-column icon">
<i class="icon-comment"></i>
</div>
<div class="header-column">
<a href="" class="grey">5 new messages</a>
</div>
-->
</div>
{% endblock %}
{# Footer branding name (center) #}
{#{% block footer_branding %}#}
{#{% endblock %}#}
{# Footer copyright (right side) #}
{#{% block copyright %}#}
{# Copyright &copy; 2013 Client<br>Developed by <a href="http://yoursite.com" target="_blank">YourName</a> #}
{#{% endblock %}#}
+19 -38
View File
@@ -1,43 +1,24 @@
{% load i18n %}
{% load static %}
{% load staticfiles %}
<link rel="stylesheet" href="{% static "css/footer.css" %}">
<footer class="footer">
<div class="container">
<div class="d-flex align-items-center justify-content-end">
<div class="p-2">
<span><i class="fa fa-copyright"></i>{% trans "Aalto-yliopiston Sähköinsinöörikilta ry" %} {% now 'Y' %}</span>
</div>
<div class="p-2">
<form class="lang-form form" action="{% url 'set_language' %}" method="post">{% csrf_token %}
<span class="form-group">
<input name="next" type="hidden" value="{{ redirect_to }}" />
<select onchange="this.form.submit()" class="lang-select form-control" name="language">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected="selected"{% endif %}>
{{ language.name_local }} ({{ language.code }})
</option>
{% endfor %}
</select>
</span>
</form>
</div>
<div class="ml-auto p-2">
<span class="nav-item">
<a href="/members"><i class="fa fa-group fa-2x"></i></a>
</span>
<span class="nav-item">
<a href="/infoscreen"><i class="fa fa-info fa-2x"></i></a>
</span>
<span class="nav-item">
<a href="/admin"><i class="fa fa-gears fa-2x"></i></a>
</span>
</div>
</div>
<div class="footer-padder"></div>
<footer style="text-align: center">
<div>
<form class="lang-form form" action="{% url 'set_language' %}" method="post">{% csrf_token %}
<span>
<input name="next" type="hidden" value="{{ redirect_to }}" />
<select onchange="this.form.submit()" class="lang-select form-control" name="language">
{% get_current_language as LANGUAGE_CODE %}
{% get_available_languages as LANGUAGES %}
{% get_language_info_list for LANGUAGES as languages %}
{% for language in languages %}
<option value="{{ language.code }}"{% if language.code == LANGUAGE_CODE %} selected="selected"{% endif %}>
{{ language.name_local }} ({{ language.code }})
</option>
{% endfor %}
</select>
</span>
</form>
<span>{% trans "Copyright Aalto-yliopiston Sähköinsinöörikilta ry" %} {% now 'Y' %}</span>
</div>
</footer>
@@ -1,6 +1,5 @@
{% load i18n %}
{% load static %}
{% load staticfiles %}
<!DOCTYPE html>
@@ -1,8 +1,7 @@
{% extends "infoscreen:base.html" %}
{% extends "infoscreen/base.html" %}
{% load i18n %}
{% load static %}
{% load staticfiles %}
{% block appname %}infoAdmin{% endblock appname %}
@@ -33,13 +32,13 @@
<h1>{% trans "Infoscreen Admin Pane" %}</h1>
</div>
</div>
{% include "infoscreen:nav.html" %}
{% include "infoscreen/nav.html" %}
<div class="tab-content" id="tabContent">
{% include "infoscreen:tabs/slides.html" %}
{% include "infoscreen:tabs/rotations.html" %}
{% include "infoscreen:tabs/add_remove.html" %}
{% include "infoscreen/tabs/slides.html" %}
{% include "infoscreen/tabs/rotations.html" %}
{% include "infoscreen/tabs/add_remove.html" %}
</div>
</div>
{% include "webapp:footer.html" %}
{% include "footer.html" %}
{% endblock body %}
@@ -1,4 +1,4 @@
{% extends "infoscreen:base.html" %}
{% extends "infoscreen/base.html" %}
{% load static %}
{% load i18n %}
@@ -26,7 +26,7 @@
<div class="col">
<div class="rotation-title-row">
<h2>{% trans "Rotation" %}: {$ selected_rot.name $}</h2>
<a class="btn btn-primary" href="/infoscreen/{$ selected_rot.id $}">{% trans "Preview" %}</a>
<a class="btn btn-primary" href="/infoscreen/{$ selected_rot.id $}">{% trans "Preview" %}</a>
</div>
<div>{% trans "Instances in currently selected rotation" %}:</div>
<table class="table table-striped">
@@ -13,13 +13,13 @@
{% block body %}
{% block header %}
<div class="kaehmy_header">
{% include "kaehmy:header.html" %}
<div class="kaehmy-header">
{% include "kaehmy/header.html" %}
</div>
{% endblock header %}
{% block navigation %}
{% include "kaehmy:navigation.html" %}
{% include "kaehmy/navigation.html" %}
{% endblock %}
<div class="kaehmy-content">
@@ -28,7 +28,7 @@
</div>
<div class="footer">
{% block footer %}
{% include "kaehmy:footer.html" %}
{% include "footer.html" %}
{% endblock footer %}
</div>
+10
View File
@@ -0,0 +1,10 @@
{% load i18n %}
<p>
Hei!
</p>
<p>
{{ name }} on vastannut kaehmyhakemukseesi tai kommenttiisi kaehmypalvelussa.
Käy lukemassa viesti
<a href={{ url }}>täältä.</a>
</p>
+13
View File
@@ -0,0 +1,13 @@
{% load i18n %}
<p>
Moikka {{ name }}!
</p>
<p>
Hienoa, että kilta kiinnostaa! Kaehmysi on vastaanotettu.
Mahdollisista kommenteista tulee ilmoitus sähköpostitse.
</p>
<p>
Käy katsomassa kaehmytilanne
<a href={{ url }}>täältä.</a>
</p>
@@ -1,4 +1,4 @@
{% extends "kaehmy:base.html" %}
{% extends "kaehmy/base.html" %}
{% load static %}
{% load i18n %}
@@ -1,4 +1,4 @@
{% extends "base.html" %}
{% extends "kaehmy/base.html" %}
{% load static %}
{% load i18n %}
@@ -18,7 +18,7 @@
<h4>{% trans "Non-board applications" %}</h4>
{{ non_board_table|safe }}
</div>
<div>
<a href="/kaehmy" class="btn btn-primary">{% trans "Front page" %}</a>
</div>
+14
View File
@@ -0,0 +1,14 @@
{% load i18n %}
<div class="kaehmy-header-content center">
<div class="kaehmy-banner logo">
<a href="/kaehmy">
<img class="kaehmy-banner-image" src="https://static.sahkoinsinoorikilta.fi/logot-ja-grafiikka/web/side/SIK_RGB_W_side.png" alt="Aalto-yliopiston Sähköinsinöörikilta ry">
</a>
</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 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>
@@ -1,10 +1,10 @@
{% extends "kaehmy:base.html" %}
{% extends "kaehmy/base.html" %}
{% load bootstrap3 %}
{% load i18n %}
{% block navigation %}
{% include "kaehmy:navigation.html" %}
{% include "kaehmy/navigation.html" %}
{% endblock %}
{% block content %}
@@ -28,10 +28,12 @@
</p>
<h5>{% trans "Päivämääriä & deadlineja" %}</h5>
<ul>
<li><strong>25.10.</strong> {% blocktrans %}Vaalikokous, osa 1 (puheenjohtajan valinta) ja hallitustyrkkypaneeli{% endblocktrans %}</li>
<li><strong>01.11.</strong> {% blocktrans %}Vaalikokous, osa 2 (hallituksen valinta){% endblocktrans %}</li>
<li><strong>09.11.</strong> {% blocktrans %}Toimikunta-appro{% endblocktrans %}</li>
<li><strong>17.11.</strong> {% blocktrans %}Vaalikokous, osa 3 (toimarien valinta){% endblocktrans %}</li>
<li><strong>11.10.</strong> {% blocktrans %}Toimikuntablää$t @Kiltis{% 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 %}
@@ -75,7 +77,13 @@
<input type="checkbox" required name="gdpr" value="1">
<span>{% blocktrans %}
Hyväksyn <a href="https://static.sahkoinsinoorikilta.fi/GDPR/Tietosuojaseloste%20%23U2013%20Toimihenkil%23U00f6ksi%20hakemisen%20rekisteri.pdf" target="_blank">tietosuojaselosteen</a> ja tietojeni tallentamisen.
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>
<input type="checkbox" name="kaehmybot" value="1" checked>
<span>{% blocktrans %}
Kähmybot saa lähettää hakemuksestani ilmoituksen killan telegramiin (hallitusvirkoihin hakiessa valitse kyllä).
{% endblocktrans %}
</span>
{% buttons %}
@@ -1,21 +1,21 @@
{% extends "kaehmy:base.html" %}
{% extends "kaehmy/base.html" %}
{% load static %}
{% load i18n %}
{% block navigation %}
{% include "kaehmy:navigation.html" %}
{% include "kaehmy/navigation.html" %}
{% endblock %}
{% block content %}
<script>
function commentOn(id, op) {
setTimeout(function() {
document.getElementById("commentNameField").focus();
document.getElementById("commentNameField").focus();
}, 50);
document.getElementById("collapse_add_comment").scrollIntoView();
document.getElementById("commentOP").innerHTML = op;
document.getElementById("collapse_add_comment").scrollIntoView();
document.getElementById("commentOP").innerHTML = op;
document.getElementById("commentId").value = id;
}
</script>
@@ -24,7 +24,7 @@
<h2 style="padding-top: 1rem">{% trans "All kaehmys" %}</h2>
</div>
<div class="collapse" id="collapse_add_comment">
<div class="collapse" id="collapse_add_comment">
<div class="card">
<div class="card-block">
<form method="POST" action="/kaehmy/add_comment" class="form">{% csrf_token %}
@@ -69,18 +69,18 @@
<div>
<h6 style="padding-bottom: 1rem">{% trans "Total kaehmys:" %} {{ application_count }}</h6>
</div>
{% for application in applications %}
<div class="card">
<h4 class="card-header">{{ application.name }}</h4>
<h4 class="card-header">{{ application.name }}</h4>
<div class="card-block">
{% if application.board_roles|length > 0 %}
<h5 style="padding-bottom: 1rem" class="card-subtitle mb-2 text-muted">{{ application.board_roles }}</h5>
<h5 style="padding-bottom: 1rem" class="card-subtitle mb-2 text-muted">{{ application.board_roles }}</h5>
{% endif %}
{% if application.official_roles|length > 0 %}
<h5 style="padding-bottom: 1rem" class="card-subtitle mb-2 text-muted">{{ application.official_roles }}</h5>
{% endif %}
<h5 style="padding-bottom: 1rem" class="card-subtitle mb-2 text-muted">{{ application.official_roles }}</h5>
{% endif %}
<p class="card-text">{{ application.text|linebreaks|urlize }}</p>
{% if application.comment_count > 0 %}
@@ -95,9 +95,9 @@
</a>
</div>
<div class="collapse" id="collapse_{{ application.id }}">
<div class="collapse" id="collapse_{{ application.id }}">
{% for message in application.messages.all %}
{% include "kaehmy:message.html" with messages=message.messages.all %}
{% include "kaehmy/message.html" with messages=message.messages.all %}
{% endfor %}
</div>
</div>
@@ -2,7 +2,7 @@
<div class="card" style="margin-top: 0.5rem; margin-bottom: 0">
<div class="card-block">
<h4>{{ message.name }}</h4>
<h4>{{ message.name }}</h4>
<p>{{ message.message|linebreaks|urlize }}</p>
<h6 class="card-subtitle mb-2 text-muted">{{ message.timestamp }}</h6>
@@ -13,9 +13,9 @@
</div>
<div>
{% for message in messages %}
{% include "message.html" with messages=message.messages.all %}
{% include "kaehmy/message.html" with messages=message.messages.all %}
{% endfor %}
</div>
</div>
</div>
@@ -1,8 +1,8 @@
{% load i18n %}
{% load static %}
<div class="kaehmy_navigation">
<nav class="navbar-border navbar navbar-toggleable-md navbar-light bg-faded">
<div class="kaehmy_navigation bg-faded">
<nav class="navbar navbar-toggleable-md navbar-light">
<div class="navbar-nav">
<a class="nav-item nav-link" href="/kaehmy">{% trans "List kaehmys" %}</a>
<a class="nav-item nav-link" href="/kaehmy/new">{% trans "New kaehmy" %} <span class="sr-only">(current)</span></a>
@@ -1,21 +1,21 @@
{% extends "kaehmy:base.html" %}
{% extends "kaehmy/base.html" %}
{% load bootstrap3 %}
{% load i18n %}
{% block navigation %}
{% include "kaehmy:navigation.html" %}
{% include "kaehmy/navigation.html" %}
{% endblock %}
{% block content %}
<div>
<div>
<h2 style="padding-top: 1rem">{% trans "Statistics" %}</h2>
<h2 style="padding-top: 1rem">{% trans "Statistics" %}</h2>
</div>
<div style="margin-top: 1rem" class="card">
<div class="card-header">
<h5>{% trans "Total kaehmys:" %} {{ application_count }}</h5>
<h5>{% trans "Total kaehmys:" %} {{ application_count }}</h5>
</div>
<div class="card-block">
{% for role in role_list %}
@@ -25,6 +25,6 @@
{% endfor %}
</div>
</div>
</div>
{% endblock content %}
@@ -1,4 +1,4 @@
{% extends "members:base.html" %}
{% extends "members/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
@@ -1,4 +1,4 @@
{% extends "members:base.html" %}
{% extends "members/base.html" %}
{% load i18n %}
{% load bootstrap3 %}
@@ -11,7 +11,7 @@
<div id="input_form">
<form name="applicationForm" action="/members/accept_application" method="post" class="form">{% csrf_token %}
<input type="hidden" name="id" value="{{ application_id }}">
<input type="hidden" name="id" value="{{ application_id }}">
{% bootstrap_form form %}
{% buttons %}
<button type="submit" class="btn btn-primary">
@@ -35,6 +35,6 @@
<body>
{% block content %}
{% endblock content %}
{% include "webapp:footer.html" %}
{% include "footer.html" %}
</body>
</html>

Some files were not shown because too many files have changed in this diff Show More