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
This commit is contained in:
Aarni Halinen
2021-05-16 14:54:43 +00:00
32 changed files with 534 additions and 985 deletions
+4
View File
@@ -1,5 +1,9 @@
[report]
show_missing = True
omit =
*/migrations/*
*/admin.py
*/translation.py
[run]
omit =
*/migrations/*
-16
View File
@@ -1,16 +0,0 @@
#!/bin/bash
echo "Deploying to development."
set -e
set -x
pushd deployment
docker-compose down
docker pull "$1"
docker-compose up -d
popd
set +x
set +e
+2 -3
View File
@@ -2,9 +2,8 @@ HOST=api.dev.sahkoinsinoorikilta.fi
DEBUG=True
SECRET_KEY=7p$85^4ibb^p4-=vs44b7!y0e-zemugze18@a#30&71=a8)dp(
TG_BOT_TOKEN=
EMAIL_HOST=
EMAIL_PASSWD=
DB_USER=postgres
DB_PASSWD=postgres
DB_HOST=db
DB_PORT=5432
DB_PORT=5432
EMAIL_API_KEY=
+2 -3
View File
@@ -2,9 +2,8 @@ HOST=localhost
DEBUG=True
SECRET_KEY=7p$85^4ibb^p4-=vs44b7!y0e-zemugze18@a#30&71=a8)dp(
TG_BOT_TOKEN=
EMAIL_HOST=
EMAIL_PASSWD=
DB_USER=postgres
DB_PASSWD=postgres
DB_HOST=db
DB_PORT=5432
DB_PORT=5432
EMAIL_API_KEY=
+7 -16
View File
@@ -1,23 +1,14 @@
*.swp
.DS_Store
.env
*~
*.pyc
*.sqlite3
uwsgi.ini
uwsgi.log
members/logs/*
.idea/
logs/
/collected_static/
/media/
logs/
members/logs/*
node_modules/
.coverage
db.sqlite3
requirements_henu.txt
/collected_static/
mydatabase
settings.json
.vscode/
.DS_Store
.idea/
*.code-workspace
sik_test
venv/
venv/
.venv/
+18 -4
View File
@@ -1,5 +1,6 @@
stages:
- setup
- audit
- lint
- test
- publish
@@ -15,8 +16,19 @@ install:
- node_modules
expire_in: 1 week
audit:
image: python:3.9
stage: audit
needs: []
before_script:
- pip install poetry==1.1.4
- poetry config virtualenvs.create false
- poetry install --no-interaction --no-ansi
script:
- safety check
test:
image: python:3.7
image: python:3.9
stage: test
needs: []
services:
@@ -27,15 +39,17 @@ test:
POSTGRES_PASSWORD: postgres
DATABASE_URL: "postgresql://postgres:postgres@postgres:5432/$POSTGRES_DB"
DB_HOST: postgres
before_script:
- pip install poetry==1.1.4
- poetry config virtualenvs.create false
- poetry install --no-interaction --no-ansi
script:
- python -V
- pip install -r requirements.txt
- python manage.py migrate --noinput
- python manage.py createdefaultadmin
- python manage.py test
lint:py:
image: python:3.7
image: python:3.9
stage: lint
needs: []
script:
+1 -1
View File
@@ -1 +1 @@
3.7.4
3.9
-1
View File
@@ -1 +0,0 @@
global_static
+22 -14
View File
@@ -1,20 +1,28 @@
FROM python:3.7-alpine
FROM python:3.9-slim-buster as builder
ENV PYTHONUNBUFFERED 1
WORKDIR /app
COPY requirements.txt ./
COPY requirements.production.txt ./
COPY . ./
# uWSGI, gunicorn etc.
RUN apk add --no-cache python3-dev build-base linux-headers pcre-dev openssl bash \
# PSQL
&& apk add --no-cache postgresql-dev \
# Pillow
&& apk add --no-cache jpeg-dev zlib-dev \
&& pip install --upgrade pip \
&& pip install -r requirements.txt \
&& pip install -r requirements.production.txt
ENV POETRY_VERSION=1.1.4
RUN pip install "poetry==$POETRY_VERSION"
RUN poetry export > requirements.txt
FROM python:3.9-slim-buster as server
WORKDIR /app
COPY . ./
COPY --from=builder requirements.txt ./
ENV PYTHONUNBUFFERED=1 \
# prevents python creating .pyc files
PYTHONDONTWRITEBYTECODE=1 \
# pip
PIP_NO_CACHE_DIR=off \
PIP_DISABLE_PIP_VERSION_CHECK=on \
PIP_DEFAULT_TIMEOUT=100
RUN apt-get update && apt-get install --no-install-recommends -y build-essential
RUN pip install -r requirements.txt
RUN python manage.py collectstatic --noinput
CMD ["sh", "-c", "./production_entrypoint.sh"]
-1
View File
@@ -13,7 +13,6 @@ services:
web:
build: .
image: registry.gitlab.com/sahkoinsinoorikilta/vtmk/web2.0-backend
command: ["bash", "-c", "cd /app & bash setup.sh --no-input --no-npm && gunicorn -w 4 -b 0.0.0.0:8000 sikweb.wsgi"]
env_file:
- .env
ports:
-5
View File
@@ -1,12 +1,7 @@
from django.db import models
from django.utils import timezone
from datetime import timedelta
from webapp.utils import month_from_now
from django.utils.translation import ugettext_lazy as _
from auditlog.registry import auditlog
from phonenumber_field.modelfields import PhoneNumberField
from webapp.models import BaseRole
import logging
# TODO: Move BaseRole to Kaehmt App; will fuck up the DB since table is removed, if no data migration is done before-hand.
-75
View File
@@ -1,75 +0,0 @@
# Linux/Mac installation instructions
## Install dependencies
### Dependency list
* Python >3.5
* PostgreSQL >9.5
* pip3
* virtualenv
* npm
Install with apt:
```bash
sudo apt install python3
sudo apt install python3-pip
sudo apt install postgresql
sudo pip3 install virtualenv
sudo apt install npm
```
More info about PostgreSQL at:
[https://www.postgresql.org/](https://www.postgresql.org)
These packages might be needed on certain platforms:
* python3-dev
* libffi-dev
* python3-cffi
* libssl-dev
## Create a virtual environment for python
Create a virtualenv in the parent directory.
```bash
virtualenv -p python3 ../virtualenv.sikweb
```
## Activate virtualenv
Assuming we are at the root of this repository and virtualenv is one level above.
```bash
. ../virtualenv.sikweb/bin/activate
```
## Run install wizard
Run the install wizard with
```bash
bash setup.sh
```
and follow the instructions.
## Done
## In case of error on macOS Mojave 10.14
If you get an error saying
```bash
The headers or library files could not be found for zlib,
a required dependency when compiling Pillow from source.
```
run
```bash
xcode-select --install
sudo installer -pkg /Library/Developer/CommandLineTools/Packages/macOS_SDK_headers_for_macOS_10.14.pkg -target /
```
+2 -2
View File
@@ -640,10 +640,10 @@ msgstr "Amazing! Your membership application has been sent."
#: members/templates/application_success.html:9
msgid ""
"Vahvistusviesti on lähetetty sähköpostiisi. Ota yhteyttä sik-vtmk@list.ayy."
"Vahvistusviesti on lähetetty sähköpostiisi. Ota yhteyttä admin@sahkoinsinoorikilta.fi."
"fi jos viestiä ei näy."
msgstr ""
"Confirmation email is sent to given email address. Contact sik-vtmk@list.ayy."
"Confirmation email is sent to given email address. Contact admin@sahkoinsinoorikilta.fi."
"fi if you didn't receive it."
#: members/templates/application_success.html:10
+4 -4
View File
@@ -453,9 +453,9 @@ msgstr "Vaalikokous, osa 3 (toimarien valinta)"
#, python-format
msgid ""
"\n"
" Hyväksyn <a href=\"https://sik.ayy.fi/files/official/"
"Tietosuojaseloste%%20%%E2%%80%%93%%20Toimihenkil%%C3%%B6ksi%%20hakemisen"
"%%20rekisteri.pdf\" target=\"_blank\">tietosuojaselosteen</a> ja tietojeni "
" Hyväksyn <a href=\"https://static.sahkoinsinoorikilta.fi/GDPR/"
"Tietosuojaseloste%20%23U2013%20Toimihenkil%23U00f6ksi%20hakemisen"
"%20rekisteri.pdf\" target=\"_blank\">tietosuojaselosteen</a> ja tietojeni "
"tallentamisen.\n"
" "
msgstr ""
@@ -637,7 +637,7 @@ msgstr "Hienoa! Jäsenhakemuksesi on nyt lähetetty."
#: members/templates/application_success.html:9
msgid ""
"Vahvistusviesti on lähetetty sähköpostiisi. Ota yhteyttä sik-vtmk@list.ayy."
"Vahvistusviesti on lähetetty sähköpostiisi. Ota yhteyttä admin@sahkoinsinoorikilta.fi."
"fi jos viestiä ei näy."
msgstr ""
+1 -1
View File
@@ -6,6 +6,6 @@
{% block content %}
<link rel="stylesheet" href="{% static "css/application.css" %}">
<h3>{% trans "Hienoa! Jäsenhakemuksesi on nyt lähetetty." %}</h3>
<p>{% trans "Vahvistusviesti on lähetetty sähköpostiisi. Ota yhteyttä sik-vtmk@list.ayy.fi jos viestiä ei näy." %}</p>
<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>
{% endblock content %}
Generated
+370 -541
View File
File diff suppressed because it is too large Load Diff
+2 -2
View File
@@ -10,8 +10,8 @@ fi
if test -f "$EMAIL_API_KEY_FILE"; then
export EMAIL_API_KEY=$(cat $EMAIL_API_KEY_FILE)
fi
if test -f "$EMAIL_API_SECRET_FILE"; then
export EMAIL_API_SECRET=$(cat $EMAIL_API_SECRET_FILE)
# if test -f "$EMAIL_API_SECRET_FILE"; then
# export EMAIL_API_SECRET=$(cat $EMAIL_API_SECRET_FILE)
fi
if test -f "$DB_USER_FILE"; then
export DB_USER=$(cat $DB_USER_FILE)
+35 -47
View File
@@ -1,59 +1,47 @@
[tool.poetry]
name = "web2.0-backend"
version = "0.1.0"
description = ""
authors = ["Your Name <you@example.com>"]
description = "Backend for sahkoinsinoorikilta.fi"
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"
djangorestframework = "^3.12.4"
djangorestframework-jwt = "^1.11.0"
django-nose = "^1.4.5"
psycopg2-binary = "^2.8.4"
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"]}
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"
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"
Markdown = "^3.2.2"
uWSGI = "^2.0.18"
gunicorn = "^20.1.0"
Pillow = "^8.1.2"
"backports.shutil_get_terminal_size" = "1.0.0"
decorator = "4.0.9"
Django = "2.1.5"
ipython = "4.2.0"
ipython_genutils = "0.1.0"
pexpect = "4.1.0"
pickleshare = "0.7.2"
ptyprocess = "0.5.1"
pytz = "2016.4"
simplegeneric = "0.8.1"
traitlets = "4.2.1"
requests = "2.11.1"
django-nocaptcha-recaptcha = "0.0.19"
django-cors-headers = "2.0.1"
djangorestframework = "3.8.2"
PyJWT = "1.6.4"
djangorestframework-jwt = "1.11.0"
coverage = "4.3.4"
django-nose = "1.4.5"
nose-exclude = "0.5.0"
psycopg2-binary = "2.8.4"
django-bootstrap3 = "11.1.0"
django-tables2 = "1.6.1"
pycodestyle = "2.6.0"
dealer = "2.0.5"
django-modeltranslation = "0.13b1"
django-auditlog = "0.4.5"
phonenumbers = "8.11.4"
django-phonenumber-field = {version = "4.0.0", extras = ["phonenumbers"]}
django-autocomplete-light = "3.4.1"
six = "1.12.0"
django-suit = "0.2.26"
telepot = "12.3"
pyexcel = "0.5.14"
pyexcel-xlsx = "0.5.8"
django-import-export = "0.7.0"
openpyxl = "2.6.4"
django-app-namespace-template-loader = "0.4.1"
django-filter = "2.0.0"
whitenoise = "4.1.4"
jsonschema = "3.2.0"
mailjet-rest = "1.3.3"
Markdown = "3.2.2"
uWSGI = "2.0.18"
gunicorn = "19.9.0"
sendgrid = "^6.7.0"
[tool.poetry.dev-dependencies]
coverage = "^5.5"
nose-exclude = "^0.5.0"
safety = "^1.10.3"
pycodestyle = "^2.7.0"
[build-system]
requires = ["poetry-core>=1.0.0"]
+1 -1
View File
@@ -12,5 +12,5 @@
"reportMissingImports": true,
"reportMissingTypeStubs": false,
"pythonVersion": "3.7.4"
"pythonVersion": "3.9"
}
+36 -25
View File
@@ -26,18 +26,39 @@ Set up your SSH key authentication in GitLab Profile Settings. Then clone the re
git clone git@gitlab.com:sahkoinsinoorikilta/vtmk/web2.0-backend.git
cd web2.0-backend
git checkout develop
cp scripts/git/pre-push .git/hooks/pre-push # install a script to test code before committing
```
## Windows install instructions
## Development
See [Windows install instructions](./windows_install.md)
### Poetry
## Linux/Mac install instructions
For depedencies and virtual environment, we use [poetry](https://python-poetry.org/). The easiest integration with VSCode is to have poetry install virtual environment in project folder, configured with
See [Linux/Mac install instructions](./linux_install.md)
```bash
poetry config virtualenvs.in-project true
```
## Initializing data
#### CMDs
Install dependencies
```bash
poetry install
```
Activate virtual environment in shell
```bash
poetry shell
```
### 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!
@@ -47,9 +68,7 @@ python manage.py initialize # creates user groups
python manage.py createdummydata # creates dummy members to the member register
```
## Running
### Use runserver command
### Running
```bash
python manage.py runserver 0.0.0.0:8000
@@ -57,23 +76,11 @@ python manage.py runserver 0.0.0.0:8000
Using address `0.0.0.0` will bind to all IP addresses. Using `localhost` will only bind to your machine.
### Visit the page
#### Visit the page
Visit [https://localhost:8000](https://localhost:8000) in your browser!
## Running in production
Run the project in production with gunicorn. Refer to [this page](https://www.digitalocean.com/community/tutorials/how-to-set-up-django-with-postgres-nginx-and-gunicorn-on-ubuntu-16-04) for instructions.
Install production dependencies.
```bash
pip install -r requirements.production.txt
```
## Development workflow
Do not use `rebase` when pulling or merging changes. Rebasing transforms the commit history and makes it appear more linear. This is a plus e.g. when working with a few people, but in this project traditional merging is recommended for clarity.
### Development workflow
When you start working on a feature, create a feature branch for your changes. These feature branches should be prefixed with `feature`.
@@ -110,13 +117,17 @@ Use an editor with linting capabilities to write pretty code that passes linting
Run unit tests with
```bash
python manage.py test -v 2
python manage.py test
```
Due to the mostly static nature of the project, most elements are difficult to properly unit test. If you write code with actual logic, make sure to write at least one unit or integration test that tests your code's core functionality.
Tests are located in `tests.py` under every subproject.
### GitLab CI
## Production
Project is run in production with Docker. See `Dockerfile` for details.
## 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`.
-2
View File
@@ -1,2 +0,0 @@
uWSGI==2.0.18
gunicorn==19.9.0
-44
View File
@@ -1,44 +0,0 @@
backports.shutil-get-terminal-size==1.0.0
decorator==4.0.9
Django==2.1.5
ipython==4.2.0
ipython-genutils==0.1.0
pexpect==4.1.0
pickleshare==0.7.2
ptyprocess==0.5.1
pytz==2016.4
simplegeneric==0.8.1
traitlets==4.2.1
Pillow==7.2.0
requests==2.11.1
django-nocaptcha-recaptcha==0.0.19
django-cors-headers==2.0.1
djangorestframework==3.8.2
PyJWT==1.6.4
djangorestframework-jwt==1.11.0
coverage==4.3.4
django-nose==1.4.5
nose-exclude==0.5.0
psycopg2-binary==2.8.4
django-bootstrap3==11.1.0
django-tables2==1.6.1
pycodestyle==2.6.0
dealer==2.0.5
django-modeltranslation==0.13b1
django-auditlog==0.4.5
phonenumbers==8.11.4
django-phonenumber-field[phonenumbers]==4.0.0
django-autocomplete-light==3.4.1
six==1.12.0
django-suit==0.2.26
telepot==12.3
pyexcel==0.5.14
pyexcel-xlsx==0.5.8
django-import-export==0.7.0
openpyxl==2.6.4
django-app-namespace-template-loader==0.4.1
django-filter==2.0.0
whitenoise==4.1.4
jsonschema==3.2.0
mailjet-rest==1.3.3
markdown==3.2.2
-68
View File
@@ -1,68 +0,0 @@
#!/bin/bash
echo "SIK WEB 2.0"
echo "This script will set up the environment for this project."
echo "========================================================="
echo "Dependencies: python3.7"
INTERACTIVE="true"
USE_NPM="true"
if [[ $* == *--no-input* ]]
then
INTERACTIVE="false"
fi
if [[ $* == *--no-npm* ]]
then
USE_NPM="false"
fi
$INTERACTIVE || (echo "Running in non-interactive mode." && env)
$INTERACTIVE && read -p "Are these programs installed? [y/n]" -n 1 -r || REPLY="y"
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]
then
echo "Please install the dependencies. Exiting."
exit 0
fi
$INTERACTIVE && read -p "Is virtualenv activated? [y/n]" -n 1 -r || REPLY="y"
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]
then
echo "Please activate virtualenv first. Exiting."
exit 0
fi
$INTERACTIVE && read -p "Copy pre-push hook to .git/hooks? (recommended) [y/n]" -n 1 -r || REPLY="y"
echo ""
if [[ $REPLY =~ ^[Yy]$ ]]
then
cp "$PWD/scripts/git/pre-push" "$PWD/.git/hooks/pre-push"
fi
$INTERACTIVE && read -p "Start setup? [y/n]" -n 1 -r || REPLY="y"
echo ""
if [[ ! $REPLY =~ ^[Yy]$ ]]
then
echo "Exiting."
exit 0
fi
set -e
set -x
pip install -r requirements.txt
pip install -r requirements.production.txt
$USE_NPM && npm install
python manage.py migrate
python manage.py createdefaultadmin
set +e
set +x
echo "Done."
echo "Run 'python manage.py runserver 0.0.0.0:8000' to start the development server!"
+4 -4
View File
@@ -203,10 +203,10 @@ REST_FRAMEWORK = {
}
# 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
# EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
# EMAIL_USE_TLS = True
# EMAIL_HOST = 'smtp.gmail.com'
# EMAIL_PORT = 587
# Internationalization
+1 -1
View File
@@ -35,7 +35,7 @@ GOOGLE_RECAPTCHA_SECRET_KEY = os.getenv("GOOGLE_RECAPTCHA_SECRET_KEY", "YOUR-PRI
# Email settings (more settings in base.py)
EMAIL_API_KEY = os.getenv('EMAIL_API_KEY', '')
EMAIL_API_SECRET = os.getenv('EMAIL_API_SECRET', '')
# EMAIL_API_SECRET = os.getenv('EMAIL_API_SECRET', '')
DEFAULT_EMAIL_FROM = 'SIK'
DEFAULT_EMAIL_FROM_ADDR = 'noreply@sahkoinsinoorikilta.fi'
ENABLE_AUTOMATIC_EMAILS = True
-4
View File
@@ -23,10 +23,6 @@ from django.conf import settings
from django.contrib.staticfiles import views as static_views
from django.views.generic.base import RedirectView
import webapp.urls
import infoscreen.urls
import members.urls
favicon_view = RedirectView.as_view(
url='static/img/favicon.png', permanent=True)
-4
View File
@@ -27,19 +27,15 @@ services:
- FRONTEND_URL=dev.sahkoinsinoorikilta.fi
- DEBUG=True
- EMAIL_API_KEY_FILE=/run/secrets/DJANGO_EMAIL_API_KEY
- EMAIL_API_SECRET_FILE=/run/secrets/DJANGO_EMAIL_API_SECRET
- DB_HOST=db
- DB_PORT=5432
secrets:
- DJANGO_EMAIL_API_KEY
- DJANGO_EMAIL_API_SECRET
secrets:
DJANGO_EMAIL_API_KEY:
external: true
DJANGO_EMAIL_API_SECRET:
external: true
volumes:
dbdata:
-4
View File
@@ -47,7 +47,6 @@ services:
- DB_HOST=db
- DB_PORT=5432
- EMAIL_API_KEY_FILE=/run/secrets/BACKEND_EMAIL_API_KEY
- EMAIL_API_SECRET_FILE=/run/secrets/BACKEND_EMAIL_API_SECRET
secrets:
- BACKEND_SECRET_KEY
@@ -55,7 +54,6 @@ services:
- BACKEND_DB_USER
- BACKEND_DB_PASSWD
- BACKEND_EMAIL_API_KEY
- BACKEND_EMAIL_API_SECRET
secrets:
BACKEND_SECRET_KEY:
external: true
@@ -69,8 +67,6 @@ secrets:
external: true
BACKEND_EMAIL_API_KEY:
external: true
BACKEND_EMAIL_API_SECRET:
external: true
volumes:
dbdata:
+1 -1
View File
@@ -6,4 +6,4 @@
<a href={{ url }}>{{url}}</a>
<p>Hädässä ota yhteyttä sik-vtmk@list.ayy.fi</p>
<p>Hädässä ota yhteyttä admin@sahkoinsinoorikilta.fi</p>
+1 -1
View File
@@ -83,7 +83,7 @@ class SignupTestCase(APITestCase):
def test_delete_signup_token(self):
pass
# TODO: Use some mocking library and check that mailjet is actually called
# TODO: Use some mocking library and check that sendgrid is actually called
def test_signupee_sendemail(self):
form = self.signupForm
emailURL = f"/api/signupForm/{form.id}/sendemail/"
+20 -35
View File
@@ -1,18 +1,16 @@
"""Webapp utils."""
from django.utils import timezone
# from django.core.mail import send_mail
import os
from mailjet_rest import Client
import sendgrid
from sendgrid.helpers.mail import *
from datetime import timedelta
import logging
from django.conf import settings
from django.template.loader import render_to_string
from django.core.files.base import ContentFile
import base64
import uuid
from sikweb.settings import FRONTEND_URL, URL, EMAIL_API_KEY, EMAIL_API_SECRET, DEFAULT_EMAIL_FROM, DEFAULT_EMAIL_FROM_ADDR, ENABLE_AUTOMATIC_EMAILS
from sikweb.settings import FRONTEND_URL, EMAIL_API_KEY, DEFAULT_EMAIL_FROM_ADDR, ENABLE_AUTOMATIC_EMAILS
import imghdr
import markdown
@@ -60,37 +58,24 @@ def send_email(to, subject, body, html=False):
logging.debug(f"subject: {subject}")
logging.debug(f"body: {body}")
return
from_email = Email(DEFAULT_EMAIL_FROM_ADDR)
to_email = To(to)
sub = Subject(subject)
if (html):
content = HtmlContent(body)
else:
content = PlainTextContent(body)
mail = Mail(from_email, to_email, sub, content)
try:
mailjet = Client(auth=(EMAIL_API_KEY, EMAIL_API_SECRET), version='v3.1')
sg = sendgrid.SendGridAPIClient(EMAIL_API_KEY)
response = sg.client.mail.send.post(request_body=mail.get())
data = {
'Messages': [
{
"From": {
"Email": DEFAULT_EMAIL_FROM_ADDR,
"Name": DEFAULT_EMAIL_FROM
},
"To": [
{
"Email": to,
"Name": "You"
}
],
"Subject": subject
}
]
}
if (html):
data["Messages"][0]["HTMLPart"] = body
else:
data["Messages"][0]["TextPart"] = body
success = mailjet.send.create(data=data)
# For some reason returns 200 OK instead of 201 Created...
if success.status_code != 200:
raise Exception(f'Failed to send email: {success.json()}')
if response.status_code != 202:
raise Exception(f'Failed to send email: {response.body}')
except Exception as ex:
logging.exception('Failed to send email.')
@@ -109,4 +94,4 @@ def send_signup_email(to, subject, id, uuid, content):
def admin_send_email_signupees(list, subject, content):
for to in list:
send_email(to, subject, markdown.markdown(content), True)
send_email(to.email, subject, markdown.markdown(content), True)
-55
View File
@@ -1,55 +0,0 @@
# Windows installation instructions
## Install dependencies
### Install python3
Visit [The python website](https://www.python.org/downloads/windows/) to install the latest version of python3.
Make sure to add the python binary directory to PATH. For instructions how to do this, refer to [this Stackoverflow answer](https://superuser.com/questions/143119/how-to-add-python-to-the-windows-path).
### Install virtualenv with pip
Run the following command to install `virtualenv`.
```cmd
python -m pip install virtualenv
```
Setup a virtual python environment.
```cmd
python -m virtualenv ../virtualenv.sikweb
```
## Activate virtualenv and install requirements
Activate `virtualenv` (note that this has to be active at all times).
```cmd
source ../virtualenv.sikweb/Scripts/activate
```
Run the following command to install python packages.
```cmd
pip install -r requirements.txt
```
## Run migrations
Run
```cmd
python manage.py migrate
```
## Install npm for linting javascript
Follow the instructions on [the npm website](https://www.npmjs.com/package/npm).
## Set up database
By default Django uses SQLite, which doesn't need any configuration. If you need PostgreSQL instead, refer to [their website](https://www.postgresql.org/download/windows/).
## Done