102 Commits

Author SHA1 Message Date
Aarni Halinen 1fa1d0c019 Fix lint 2022-08-06 17:48:48 +03:00
Aarni Halinen 4419f1cf2c Fix nginx_jwt_resp HTTP responses 2022-08-06 17:46:29 +03:00
Aarni Halinen 6e74548206 Fix tests 2022-08-06 17:46:27 +03:00
Aarni Halinen 5b9b4021d3 Fix serializer 2022-08-06 17:46:25 +03:00
Aarni Halinen 05279ae900 Implement filter for publishAt 2022-08-06 17:46:22 +03:00
Aarni Halinen 9b450f94a5 Rewrite Event and JobAd get_queryset 2022-08-06 17:46:17 +03:00
Aarni Halinen 7ffce4e929 Rewrite Feed get_queryset 2022-08-06 17:46:12 +03:00
Aarni Halinen ca8937d9f6 Rename BaseFeed fields 2022-08-06 17:46:04 +03:00
Aarni Halinen 92f744f39c Re-order views and serializers 2022-08-06 17:45:38 +03:00
Aarni Halinen 7c9a627d41 Require explicit publishing from creator 2022-08-06 17:45:35 +03:00
Aarni Halinen a35b86af43 Rename BaseFeed fields 2022-08-06 17:45:01 +03:00
Aarni Halinen 9651725bb3 Audit log register for TemplateQuestions 2022-08-06 17:44:10 +03:00
Aarni Halinen ac017bfb82 Remove created_at from JobAd 2022-08-06 17:44:08 +03:00
Aarni Halinen f923511a72 Re-order models 2022-08-06 17:43:18 +03:00
Aarni Halinen 78092ce734 Fix field name 2022-08-06 17:40:00 +03:00
Aarni Halinen ae136aebae Remove OldJobAd model 2022-08-06 17:39:59 +03:00
Aarni Halinen 1eb5e7e10c Add missing fields for new JobAd 2022-08-06 17:38:43 +03:00
Aarni Halinen 74d0765eb2 Data migration for JobAds 2022-08-06 17:38:41 +03:00
Aarni Halinen 1cab37dbcf Add new JobAd model 2022-08-06 17:38:02 +03:00
Aarni Halinen cf673c32c5 Rename old JobAd model 2022-08-06 17:37:28 +03:00
Aarni Halinen a2e6a4754e Remove duplicate code 2022-08-06 17:36:36 +03:00
Aarni Halinen 6ccb1d01cf Rename and remove moved fields 2022-08-06 17:36:34 +03:00
Aarni Halinen cd708a469d Add new base fields 2022-08-06 17:33:37 +03:00
Aarni Halinen 831f15d0ff Reorder fields 2022-08-06 17:32:53 +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 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 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
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
Ojakoo ec4317d9e7 heevi email fix 2022-05-25 19:13:16 +03: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
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
141 changed files with 2244 additions and 1614 deletions
+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
+2
View File
@@ -9,3 +9,5 @@ DB_PASSWD=postgres
DB_HOST=db
DB_PORT=5432
EMAIL_API_KEY=
GROUP_KEY=
GOOGLE_CREDS_JSON='{}'
+1 -1
View File
@@ -11,4 +11,4 @@ node_modules/
.idea/
*.code-workspace
venv/
.venv/
.venv/
+3 -3
View File
@@ -21,7 +21,7 @@ audit:
stage: audit
needs: []
before_script:
- pip install poetry==1.1.4
- pip install poetry==1.1.13
- poetry config virtualenvs.create false
- poetry install --no-interaction --no-ansi
script:
@@ -40,7 +40,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.1.13
- poetry config virtualenvs.create false
- poetry install --no-interaction --no-ansi
script:
@@ -53,7 +53,7 @@ lint:py:
stage: lint
needs: []
script:
- pip install black==21.12b0
- pip install black==22.3.0
- black --check .
lint:js:
+15
View File
@@ -0,0 +1,15 @@
#!/bin/sh
. "$(dirname "$0")/_/husky.sh"
PURPLE='\033[0;35m'
NC='\033[0m' # No Color
source "${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
+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.1.13
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"]
@@ -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),
),
]
+5
View File
@@ -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>
+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"])
+3 -3
View File
@@ -2,11 +2,11 @@ from django import forms
from django.utils.translation import ugettext_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"
option_template_name = "kaehmy/checkbox_option.html"
def create_option(
self, name, value, label, selected, index, subindex=None, attrs=None
@@ -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",
),
]
+13 -12
View File
@@ -1,20 +1,16 @@
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
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 = (
("corporate", _("Corporate affairs")),
@@ -35,8 +31,12 @@ class KaehmyBaseRole(BaseRole):
_("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 +46,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 +56,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)
-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>
+8 -12
View File
@@ -1,15 +1,11 @@
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
import logging
import requests
from dealer.git import git
from sikweb.settings import URL
from members.views.utils import *
@@ -56,7 +52,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
@@ -81,7 +77,7 @@ def comment(request, *args, **kwargs):
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 +102,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
@@ -148,7 +144,7 @@ def submit(request, *args, **kwargs):
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 +171,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)
+2 -2
View File
@@ -1059,9 +1059,9 @@ msgid "-sarjassa"
msgstr "series"
#: ohlhafv/templates/email.html:8
msgid "Muistattehan vahvistaa haasteen paikan päällä Smökissä torstaina 14.2"
msgid "Muistattehan vahvistaa haasteen paikan päällä Smökissä torstaina 26.5."
msgstr ""
"Remeber to confirm the challenge at Smökki on Thursday 14.2. at the event"
"Remeber to confirm the challenge at Smökki on Thursday 26.5. at the event"
#: ohlhafv/templates/email.html:10
msgid "Käy kurkkaamassa muutkin haasteet osoitteessa"
+1 -1
View File
@@ -1045,7 +1045,7 @@ msgid "-sarjassa"
msgstr ""
#: ohlhafv/templates/email.html:8
msgid "Muistattehan vahvistaa haasteen paikan päällä Smökissä torstaina 14.2"
msgid "Muistattehan vahvistaa haasteen paikan päällä Smökissä torstaina 26.5."
msgstr ""
#: ohlhafv/templates/email.html:10
@@ -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),
),
]
+2
View File
@@ -9,6 +9,7 @@ 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,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",
+14 -8
View File
@@ -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)
+9 -5
View File
@@ -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")
+8 -4
View File
@@ -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},
)
+3 -3
View File
@@ -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
@@ -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):
@@ -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),
),
]
+1
View File
@@ -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"))
Binary file not shown.

Before

Width:  |  Height:  |  Size: 234 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 MiB

-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>
+4 -4
View File
@@ -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
+483 -487
View File
File diff suppressed because it is too large Load Diff
+3
View File
@@ -10,6 +10,9 @@ fi
if test -f "$DB_PASSWD_FILE"; then
export DB_PASSWD=$(cat $DB_PASSWD_FILE)
fi
if test -f "$GOOGLE_CREDS_JSON"; then
export GOOGLE_CREDS_JSON=$(cat $GOOGLE_CRED_JSON_FILE)
fi
# Collect static files
echo "Collect static files"
+21 -22
View File
@@ -7,43 +7,42 @@ 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 = "^3.2.14"
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"
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"
[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;
+23 -92
View File
@@ -7,14 +7,26 @@ from django.utils.translation import ugettext_lazy as _
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
# 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)
+54 -17
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,21 +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
# 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"),
@@ -74,3 +79,35 @@ DATABASES = {
"OPTIONS": DB_OPTIONS,
}
}
# Google api settings
GROUP_KEY = os.getenv("GROUP_KEY", "")
GOOGLE_SERVICE_ACCOUNT = json.loads(os.getenv("GOOGLE_CREDS_JSON", "{}"))
# 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),
}
+4
View File
@@ -34,11 +34,13 @@ services:
- SECRET_KEY_FILE=/run/secrets/BACKEND_SECRET_KEY
- DB_PASSWD_FILE=/run/secrets/BACKEND_DB_PASSWD
- EMAIL_API_KEY_FILE=/run/secrets/BACKEND_EMAIL_API_KEY
- GOOGLE_CREDS_JSON=/run/secrets/GOOGLE_CREDS_JSON
secrets:
- BACKEND_SECRET_KEY
- BACKEND_DB_PASSWD
- BACKEND_EMAIL_API_KEY
- GOOGLE_CREDS_JSON
secrets:
BACKEND_SECRET_KEY:
external: true
@@ -46,3 +48,5 @@ secrets:
external: true
BACKEND_EMAIL_API_KEY:
external: true
GOOGLE_CREDS_JSON:
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">
@@ -14,12 +14,12 @@
{% block header %}
<div class="kaehmy_header">
{% include "kaehmy:header.html" %}
{% 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>
@@ -1,4 +1,4 @@
{% extends "kaehmy: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>
@@ -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 %}
@@ -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>
@@ -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,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>
@@ -1,4 +1,4 @@
{% extends "application_form_base.html" %}
{% extends "members/application_form_base.html" %}
{% load static %}
{% load bootstrap3 %}
{% load i18n %}
@@ -1,4 +1,4 @@
{% extends "members:base.html" %}
{% extends "members/base.html" %}
{% load i18n %}
@@ -17,7 +17,7 @@
{{ table|safe }}
<div>
<a href="/members/export_applications" class="btn btn-info">{% trans "Download Excel" %}</a>
<a href="/members/export_applications" class="btn btn-info">{% trans "Download Excel" %}</a>
</div>
</div>
@@ -1,4 +1,4 @@
{% extends "application_form_base.html" %}
{% extends "members/application_form_base.html" %}
{% load static %}
{% load bootstrap3 %}
{% load i18n %}
@@ -7,5 +7,5 @@
<link rel="stylesheet" href="{% static "css/application.css" %}">
<h3>{% trans "Hienoa! Jäsenhakemuksesi on nyt lähetetty." %}</h3>
<p>{% trans "Vahvistusviesti on lähetetty sähköpostiisi. Ota yhteyttä admin@sahkoinsinoorikilta.fi jos viestiä ei näy." %}</p>
<a href="/"><h4>{% trans "Takaisin Sähköinsinöörikillan web-sivuille" %}</h4></a>
<a href="https://sahkoinsinoorikilta.fi/"><h4>{% trans "Takaisin Sähköinsinöörikillan web-sivuille" %}</h4></a>
{% endblock content %}
@@ -1,6 +1,5 @@
<!DOCTYPE html>
{% load staticfiles %}
{% load static %}
{% load i18n %}
@@ -92,6 +91,6 @@
</div>
</div>
{% include "webapp:footer.html" %}
{% include "footer.html" %}
</body>
</html>
@@ -0,0 +1,15 @@
{% load i18n %}
<p>Moi {{first_name}}!</p>
<p>Onnittelut! Sinut on hyväksytty Sähköinsinöörikillan jäseneksi.</p>
<p>
Käy kurkkaamassa killan
<a href="https://sahkoinsinoorikilta.fi">nettisivuilta</a>
tulevia tapahtumia ja piipahda kiltahuoneella tutustumassa uusiin kiltatovereihisi!
</p>
<p>Liity myös killan TG-kanaville:</p>
<p><a href="https://t.me/+ubTeGSYKTvg3NmVk">Killan yleinen telegram</a></p>
<p><a href="https://t.me/+1PqQHRVMjiAxMTU0">SIK-fuksit 2022</a></p>
<p><a href="https://t.me/+Ln8TvQ-_id9kZTU0">SIK-fuksit 2022 -tiedotuskanava</a></p>
@@ -1,4 +1,4 @@
{% extends "members:base.html" %}
{% extends "members/base.html" %}
{% load static %}
{% load i18n %}
@@ -1,4 +1,4 @@
{% extends "members:base.html" %}
{% extends "members/base.html" %}
{% load bootstrap3 %}
{% load i18n %}
@@ -1,4 +1,4 @@
{% extends "members:base.html" %}
{% extends "members/base.html" %}
{% load i18n %}
{% load static %}
@@ -11,7 +11,7 @@
<div>
<p>
{% blocktrans %}
Enter member information in CSV format, separate members on separate lines.
Enter member information in CSV format, separate members on separate lines.
If a new member already exists in the database, a new payment event will be created for that member instead.
{% endblocktrans %}
</p>
@@ -20,7 +20,7 @@
<div>
<label>{% trans "Format the member table like this:" %}</label>
<div>
<img src="{% static "members/img/excel_csv_save_example.png" %}">
<img src="{% static "members/img/excel_csv_save_example.png" %}">
</div>
<p>{% blocktrans %}Columns: First name, last name, email address, place of origin, AYY member, JAS recipient{% endblocktrans %}</p>
</div>
@@ -28,10 +28,10 @@
<label>{% trans "Save the file as CSV" %}</label>
<div><img src="{% static "members/img/excel_csv_save_tutorial.png" %}"></div>
</div>
<form name="memberTextForm" action="/members/import_csv" enctype="multipart/form-data" method="POST">{% csrf_token %}
<h3>{% trans "Upload file" %}</h3>
<input class="form-control-file" type="file" accept=".csv" name="csvFile" />
<input class="form-control-file" type="file" accept=".csv" name="csvFile" />
<div class="form-group">
<label>{% trans "Payment source" %}</label>
@@ -42,7 +42,7 @@
</select>
<small class="form-text text-muted">
{% trans "This payment source will be used to create any payments for new members that already exist in the database." %}
</small>
</small>
</div>
<div class="form-group">
<label>{% trans "CSV delimiter" %}</label>
@@ -1,4 +1,4 @@
{% extends "members:base.html" %}
{% extends "members/base.html" %}
{% load i18n %}
@@ -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 %}
@@ -1,4 +1,4 @@
{% extends "members:base.html" %}
{% extends "members/base.html" %}
{% load static %}
{% load i18n %}
@@ -41,7 +41,7 @@
{{ table|safe }}
<div>
<a href="/members/export_members" class="btn btn-info">{% trans "Download Excel" %}</a>
<a href="/members/export_members" class="btn btn-info">{% trans "Download Excel" %}</a>
</div>
</div>
{% endblock content %}
@@ -1,4 +1,4 @@
{% extends "members:base.html" %}
{% extends "members/base.html" %}
{% load bootstrap3 %}
{% load i18n %}
@@ -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 %}
@@ -1,4 +1,4 @@
{% extends "members:base.html" %}
{% extends "members/base.html" %}
{% load static %}
{% load i18n %}
@@ -38,7 +38,7 @@
{{ table|safe }}
<div>
<a href="/members/export_payments" class="btn btn-info">{% trans "Download Excel" %}</a>
<a href="/members/export_payments" class="btn btn-info">{% trans "Download Excel" %}</a>
</div>
</div>
{% endblock content %}
@@ -1,4 +1,4 @@
{% extends "members:base.html" %}
{% extends "base.html" %}
{% load static %}
{% load i18n %}
@@ -1,10 +1,10 @@
{% extends "members:base.html" %}
{% extends "members/base.html" %}
{% block content %}
<h1>{{ title }}</h1>
<h3>{{ header }}</h3>
<form method="POST" action="/members/import_excel" enctype="multipart/form-data">{% csrf_token %}
{{ form }}
<input type="submit" class="btn btn-primary">
<input type="submit" class="btn btn-primary">
</form>
{% endblock %}
@@ -7,22 +7,23 @@
<link rel="stylesheet" href="{% static "ohlhafv/css/base.css" %}">
<link rel="stylesheet" href="{% static "ohlhafv/css/header.css" %}">
<link rel="stylesheet" href="{% static "ohlhafv/css/nav.css" %}">
<link rel="stylesheet" href="{% static "ohlhafv/css/footer.css" %}">
{% endblock styles %}
{% block body %}
{% block header %}
{% include "ohlhafv:header.html" %}
{% include "ohlhafv/header.html" %}
{% endblock header %}
{% block navigation %}
{% include "ohlhafv:navigation.html" %}
{% include "ohlhafv/navigation.html" %}
{% endblock %}
{% block content %}
{% endblock %}
{% block footer %}
{% include "ohlhafv:footer.html" %}
{% include "footer.html" %}
{% endblock footer %}
{% endblock body %}
@@ -5,6 +5,6 @@
{{ challenge.message }}
{% trans "Muistattehan vahvistaa haasteen paikan päällä Smökissä torstaina 14.2" %}.
{% trans "Muistattehan vahvistaa haasteen paikan päällä Smökissä torstaina 26.5" %}.
{% trans "Käy kurkkaamassa muutkin haasteet osoitteessa" %} {{ url }}
@@ -1,4 +1,4 @@
{% extends "ohlhafv:base.html" %}
{% extends "ohlhafv/base.html" %}
{% load static %}
{% load i18n %}
@@ -14,7 +14,7 @@
{% for challenge in challenges %}
<div class="card">
<h4 class="card-header">{{ challenge.challenger }} vs. {{ challenge.victim }}</h4>
<h4 class="card-header">{{ challenge.challenger }} vs. {{ challenge.victim }}</h4>
<div class="card-block">
<h5 class="card-subtitle mb-2">{{ challenge.get_series_display }}</h5>
<p class="card-text">{{ challenge.message|linebreaks|urlize }}</p>
@@ -1,10 +1,10 @@
{% extends "ohlhafv:base.html" %}
{% extends "ohlhafv/base.html" %}
{% load bootstrap3 %}
{% load i18n %}
{% block navigation %}
{% include "ohlhafv:navigation.html" %}
{% include "ohlhafv/navigation.html" %}
{% endblock %}
{% block content %}

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