Unique emails and added can_receive
This commit is contained in:
parent
ba580483b4
commit
aff7bf3b48
@ -1,7 +1,12 @@
|
|||||||
FROM python:3.8.1
|
FROM python:3.8.12-slim-buster
|
||||||
|
|
||||||
RUN apt-get -y update && apt-get -y upgrade && \
|
RUN apt-get -y update && apt-get -y upgrade && \
|
||||||
apt-get install --no-install-recommends -y wait-for-it postgresql-client
|
apt-get install --no-install-recommends -y wait-for-it lsb-release wget gnupg2 gcc libpq-dev libc-dev
|
||||||
|
|
||||||
|
# install psql 13 (11 is the default with debian)
|
||||||
|
RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | sudo apt-key add -
|
||||||
|
RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" |sudo tee /etc/apt/sources.list.d/pgdg.list
|
||||||
|
RUN apt-get update && apt-get --no-install-recommends -y install postgresql-client-13 && apt-get clean all
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,12 @@
|
|||||||
FROM python:3.8.1
|
FROM python:3.8.12-slim-buster
|
||||||
|
|
||||||
RUN apt-get -y update && apt-get -y upgrade && \
|
RUN apt-get -y update && apt-get -y upgrade && \
|
||||||
apt-get install --no-install-recommends -y wait-for-it postgresql-client vim
|
apt-get install --no-install-recommends -y wait-for-it lsb-release wget gnupg2 gcc libpq-dev libc-dev vim
|
||||||
|
|
||||||
|
# install psql 13 (11 is the default with debian)
|
||||||
|
RUN wget --quiet -O - https://www.postgresql.org/media/keys/ACCC4CF8.asc | apt-key add -
|
||||||
|
RUN echo "deb http://apt.postgresql.org/pub/repos/apt/ `lsb_release -cs`-pgdg main" | tee /etc/apt/sources.list.d/pgdg.list
|
||||||
|
RUN apt-get update && apt-get --no-install-recommends -y install postgresql-client-13 && apt-get clean all
|
||||||
|
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
|
|||||||
8
Makefile
8
Makefile
@ -14,11 +14,17 @@ run-bash: | build-dev
|
|||||||
docker-compose -f dc.dev.yml exec -u $$(id -u $${USER}):$$(id -g $${USER}) max bash || true
|
docker-compose -f dc.dev.yml exec -u $$(id -u $${USER}):$$(id -g $${USER}) max bash || true
|
||||||
docker-compose -f dc.dev.yml down
|
docker-compose -f dc.dev.yml down
|
||||||
|
|
||||||
|
run-bash-root: | build-dev
|
||||||
|
MAX_COMMAND="sleep infinity" docker-compose -f dc.dev.yml up -d
|
||||||
|
docker-compose -f dc.dev.yml exec max "./entrypoint-dev.sh"
|
||||||
|
docker-compose -f dc.dev.yml exec max bash || true
|
||||||
|
docker-compose -f dc.dev.yml down
|
||||||
|
|
||||||
stop-dev:
|
stop-dev:
|
||||||
docker-compose -f dc.dev.yml down
|
docker-compose -f dc.dev.yml down
|
||||||
|
|
||||||
run-cleanup: | build-dev
|
run-cleanup: | build-dev
|
||||||
docker run -ti -v `pwd`/max:/app/max max-dev ./cleanup.sh
|
docker run -ti -v `pwd`/max:/app/max --entrypoint="" max-dev ./cleanup.sh
|
||||||
|
|
||||||
# PROD
|
# PROD
|
||||||
|
|
||||||
|
|||||||
@ -12,6 +12,7 @@ class Alias(NoteLinesMixin):
|
|||||||
email: str
|
email: str
|
||||||
destination_user_id: int
|
destination_user_id: int
|
||||||
enabled: bool
|
enabled: bool
|
||||||
|
can_receive: bool
|
||||||
note: str
|
note: str
|
||||||
|
|
||||||
|
|
||||||
@ -35,8 +36,9 @@ def get_aliases(cur, user_id):
|
|||||||
def get_alias_with_user_by_id(cur, alias_id):
|
def get_alias_with_user_by_id(cur, alias_id):
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"""\
|
"""\
|
||||||
SELECT a.id, a.source_email_id, ea.email, a.destination_user_id, a.enabled, a.note,
|
SELECT a.id, a.source_email_id, ea.email, a.destination_user_id, a.enabled,
|
||||||
u.id, u.email_id, eu.email, u.passwordhash, u.enabled, u.is_admin, u.note
|
a.can_receive, a.note,
|
||||||
|
u.id, u.email_id, eu.email, u.passwordhash, u.enabled, u.can_receive, u.is_admin, u.note
|
||||||
FROM aliases a
|
FROM aliases a
|
||||||
INNER JOIN emails ea ON a.source_email_id=ea.id
|
INNER JOIN emails ea ON a.source_email_id=ea.id
|
||||||
INNER JOIN users u ON a.destination_user_id=u.id
|
INNER JOIN users u ON a.destination_user_id=u.id
|
||||||
@ -47,23 +49,23 @@ def get_alias_with_user_by_id(cur, alias_id):
|
|||||||
row = cur.fetchone()
|
row = cur.fetchone()
|
||||||
if not row:
|
if not row:
|
||||||
return None
|
return None
|
||||||
return Alias(*row[:6]), User(*row[6:])
|
return Alias(*row[:7]), User(*row[7:])
|
||||||
|
|
||||||
|
|
||||||
@with_cursor
|
@with_cursor
|
||||||
def create_alias(cur, email, user, enabled, note):
|
def create_alias(cur, email, user, enabled, can_receive, note):
|
||||||
email_id = create_email(cur, email)
|
email_id = create_email(cur, email)
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"""
|
"""
|
||||||
INSERT INTO aliases (source_email_id, destination_user_id, enabled, note)
|
INSERT INTO aliases (source_email_id, destination_user_id, enabled, can_receive, note)
|
||||||
VALUES (%s, %s, %s, %s)""",
|
VALUES (%s, %s, %s, %s, %s)""",
|
||||||
[email_id, user.id, enabled, note],
|
[email_id, user.id, enabled, can_receive, note],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@with_cursor
|
@with_cursor
|
||||||
def update_alias(cur, id, **fields):
|
def update_alias(cur, id, **fields):
|
||||||
"""updates enabled and note"""
|
"""updates enabled, can_receive and note"""
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"UPDATE aliases SET "
|
"UPDATE aliases SET "
|
||||||
+ ", ".join(f"{field}=%s" for field in fields.keys())
|
+ ", ".join(f"{field}=%s" for field in fields.keys())
|
||||||
|
|||||||
@ -6,15 +6,17 @@ class EmailAlreadyExists(Exception):
|
|||||||
|
|
||||||
class NoteLinesMixin:
|
class NoteLinesMixin:
|
||||||
def note_lines(self):
|
def note_lines(self):
|
||||||
return [line.strip() for line in self.note.split("\n")]
|
if not self.note.strip():
|
||||||
|
return []
|
||||||
|
return [line.strip() for line in self.note.strip().split("\n")]
|
||||||
|
|
||||||
|
|
||||||
def create_email(cur, email):
|
def create_email(cur, email):
|
||||||
cur.execute("SELECT EXISTS (SELECT 1 FROM emails WHERE email=%s)", [email])
|
cur.execute("SELECT EXISTS (SELECT 1 FROM emails WHERE email=lower(%s))", [email])
|
||||||
email_exists = cur.fetchone()[0]
|
email_exists = cur.fetchone()[0]
|
||||||
|
|
||||||
if email_exists:
|
if email_exists:
|
||||||
cur.execute("SELECT id FROM emails WHERE email=%s", [email])
|
cur.execute("SELECT id FROM emails WHERE email=lower(%s)", [email])
|
||||||
email_id = cur.fetchone()[0]
|
email_id = cur.fetchone()[0]
|
||||||
|
|
||||||
# Get user?
|
# Get user?
|
||||||
@ -35,6 +37,8 @@ def create_email(cur, email):
|
|||||||
raise EmailAlreadyExists("Used as an user.")
|
raise EmailAlreadyExists("Used as an user.")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
cur.execute("INSERT INTO emails (email) VALUES (%s) RETURNING id", [email])
|
cur.execute(
|
||||||
|
"INSERT INTO emails (email) VALUES (lower(%s)) RETURNING id", [email]
|
||||||
|
)
|
||||||
email_id = cur.fetchone()[0]
|
email_id = cur.fetchone()[0]
|
||||||
return email_id
|
return email_id
|
||||||
|
|||||||
@ -7,20 +7,26 @@ CREATE TABLE IF NOT EXISTS emails (
|
|||||||
email varchar(255) NOT NULL UNIQUE
|
email varchar(255) NOT NULL UNIQUE
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- Make emails unique by lower-case comparison
|
||||||
|
CREATE UNIQUE INDEX email_unique_idx on emails (LOWER(email));
|
||||||
|
|
||||||
CREATE TABLE IF NOT EXISTS users (
|
CREATE TABLE IF NOT EXISTS users (
|
||||||
id serial PRIMARY KEY,
|
id serial PRIMARY KEY,
|
||||||
email_id integer REFERENCES emails(id) ON DELETE RESTRICT NOT NULL UNIQUE,
|
email_id integer REFERENCES emails(id) ON DELETE RESTRICT NOT NULL UNIQUE,
|
||||||
passwordhash varchar(255) NOT NULL,
|
passwordhash varchar(255) NOT NULL,
|
||||||
enabled boolean NOT NULL DEFAULT TRUE,
|
enabled boolean NOT NULL DEFAULT TRUE,
|
||||||
|
can_receive boolean NOT NULL DEFAULT TRUE,
|
||||||
is_admin boolean NOT NULL DEFAULT FALSE,
|
is_admin boolean NOT NULL DEFAULT FALSE,
|
||||||
note text NOT NULL DEFAULT ''
|
note text NOT NULL DEFAULT ''
|
||||||
);
|
);
|
||||||
|
|
||||||
|
-- source=me2@finn.st destination=me@finn.st: me2 is an alias of me
|
||||||
CREATE TABLE IF NOT EXISTS aliases (
|
CREATE TABLE IF NOT EXISTS aliases (
|
||||||
id serial PRIMARY KEY,
|
id serial PRIMARY KEY,
|
||||||
source_email_id integer REFERENCES emails(id) ON DELETE RESTRICT NOT NULL,
|
source_email_id integer REFERENCES emails(id) ON DELETE RESTRICT NOT NULL,
|
||||||
destination_user_id integer REFERENCES users(id) ON DELETE RESTRICT NOT NULL,
|
destination_user_id integer REFERENCES users(id) ON DELETE RESTRICT NOT NULL,
|
||||||
enabled boolean NOT NULL DEFAULT TRUE,
|
enabled boolean NOT NULL DEFAULT TRUE,
|
||||||
|
can_receive boolean NOT NULL DEFAULT TRUE,
|
||||||
note text,
|
note text,
|
||||||
UNIQUE(source_email_id, destination_user_id)
|
UNIQUE(source_email_id, destination_user_id)
|
||||||
);
|
);
|
||||||
|
|||||||
@ -11,6 +11,7 @@ class User(NoteLinesMixin):
|
|||||||
email: str
|
email: str
|
||||||
passwordhash: str
|
passwordhash: str
|
||||||
enabled: bool
|
enabled: bool
|
||||||
|
can_receive: bool
|
||||||
is_admin: bool
|
is_admin: bool
|
||||||
note: str
|
note: str
|
||||||
|
|
||||||
@ -52,7 +53,7 @@ def get_users(cur):
|
|||||||
|
|
||||||
@with_cursor
|
@with_cursor
|
||||||
def update_user(cur, id, **fields):
|
def update_user(cur, id, **fields):
|
||||||
"""only pwhash, enabled, is_admin, note"""
|
"""only pwhash, enabled, can_receive, is_admin, note"""
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"UPDATE users SET "
|
"UPDATE users SET "
|
||||||
+ ", ".join(f"{field}=%s" for field in fields.keys())
|
+ ", ".join(f"{field}=%s" for field in fields.keys())
|
||||||
@ -62,13 +63,13 @@ def update_user(cur, id, **fields):
|
|||||||
|
|
||||||
|
|
||||||
@with_cursor
|
@with_cursor
|
||||||
def create_user(cur, email, passwordhash, enabled, is_admin, note):
|
def create_user(cur, email, passwordhash, enabled, can_receive, is_admin, note):
|
||||||
email_id = create_email(cur, email)
|
email_id = create_email(cur, email)
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"""\
|
"""\
|
||||||
INSERT INTO users (email_id, passwordhash, enabled, is_admin, note)
|
INSERT INTO users (email_id, passwordhash, enabled, can_receive, is_admin, note)
|
||||||
VALUES (%s, %s, %s, %s, %s)""",
|
VALUES (%s, %s, %s, %s, %s, %s)""",
|
||||||
[email_id, passwordhash, enabled, is_admin, note],
|
[email_id, passwordhash, enabled, can_receive, is_admin, note],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -92,8 +93,8 @@ def reset_or_create_user(cur, email, hash, is_admin):
|
|||||||
user_id = user_id[0]
|
user_id = user_id[0]
|
||||||
# update User
|
# update User
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"UPDATE users SET passwordhash=%s, is_admin=%s, enabled=%s WHERE id=%s",
|
"UPDATE users SET passwordhash=%s, is_admin=%s, enabled=%s can_receive=%s WHERE id=%s", # noqa
|
||||||
[hash, is_admin, True, user_id],
|
[hash, is_admin, True, True, user_id],
|
||||||
)
|
)
|
||||||
print(
|
print(
|
||||||
f"reset password for {email}. Set admin={is_admin} and enabled the user."
|
f"reset password for {email}. Set admin={is_admin} and enabled the user."
|
||||||
@ -105,8 +106,8 @@ def reset_or_create_user(cur, email, hash, is_admin):
|
|||||||
cur.execute("INSERT INTO emails (email) VALUES (%s) RETURNING id", [email])
|
cur.execute("INSERT INTO emails (email) VALUES (%s) RETURNING id", [email])
|
||||||
email_id = cur.fetchone()[0]
|
email_id = cur.fetchone()[0]
|
||||||
cur.execute(
|
cur.execute(
|
||||||
"INSERT INTO users (email_id, passwordhash, enabled, is_admin, note) VALUES (%s, %s, %s, %s, %s)", # noqa
|
"INSERT INTO users (email_id, passwordhash, enabled, can_receive, is_admin, note) VALUES (%s, %s, %s, %s, %s, %s)", # noqa
|
||||||
[email_id, hash, True, is_admin, "Created by commandline"],
|
[email_id, hash, True, True, is_admin, "Created by commandline"],
|
||||||
)
|
)
|
||||||
user_type = "admin" if is_admin else "user"
|
user_type = "admin" if is_admin else "user"
|
||||||
print(f"Created {user_type} {email}")
|
print(f"Created {user_type} {email}")
|
||||||
|
|||||||
@ -58,7 +58,7 @@ class ExceptionMiddleware(BaseMiddleware):
|
|||||||
def __call__(self, *args, **kwargs):
|
def __call__(self, *args, **kwargs):
|
||||||
try:
|
try:
|
||||||
return self.handler(*args, **kwargs)
|
return self.handler(*args, **kwargs)
|
||||||
except (NotFound, PermissionDenied) as e:
|
except (NotFound, PermissionDenied):
|
||||||
notFoundView = NotFoundView(**kwargs)
|
notFoundView = NotFoundView(**kwargs)
|
||||||
return notFoundView.render(), 404
|
return notFoundView.render(), 404
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
from max.permissions import AllowAnyAccess
|
from max.permissions import AllowAnyAccess
|
||||||
from max.views import BaseTemplateGetView
|
|
||||||
from max.translations import t
|
from max.translations import t
|
||||||
|
from max.views import BaseTemplateGetView
|
||||||
|
|
||||||
|
|
||||||
class NotFoundView(AllowAnyAccess, BaseTemplateGetView):
|
class NotFoundView(AllowAnyAccess, BaseTemplateGetView):
|
||||||
|
|||||||
@ -19,6 +19,7 @@
|
|||||||
"Create new user": "Neuen Nutzer erstellen",
|
"Create new user": "Neuen Nutzer erstellen",
|
||||||
"Create": "Erstellen",
|
"Create": "Erstellen",
|
||||||
"Enabled": "Aktiviert",
|
"Enabled": "Aktiviert",
|
||||||
|
"Can receive emails": "Kann Emails empfangen",
|
||||||
"Admin": "Admin",
|
"Admin": "Admin",
|
||||||
"Note": "Notiz",
|
"Note": "Notiz",
|
||||||
"Delete {user}?": "{user} löschen?",
|
"Delete {user}?": "{user} löschen?",
|
||||||
@ -47,6 +48,7 @@
|
|||||||
"The domain is invalid. Must be one of: {domains}": "Die Domain ist nacht valide. Dies sind die erlaubten Domains: {domains}",
|
"The domain is invalid. Must be one of: {domains}": "Die Domain ist nacht valide. Dies sind die erlaubten Domains: {domains}",
|
||||||
"Email must be given": "Die Email muss gegeben sein",
|
"Email must be given": "Die Email muss gegeben sein",
|
||||||
"Enabled is not set": "Aktiviert ist nicht gesetzt",
|
"Enabled is not set": "Aktiviert ist nicht gesetzt",
|
||||||
|
"Can receive is not set": "Kann empfangen ist nicht gesetzt",
|
||||||
"Note must be a string": "Die Notiz muss eine Zeichenkette sein",
|
"Note must be a string": "Die Notiz muss eine Zeichenkette sein",
|
||||||
"Creation of alias {email} was successful!": "Erstellen des Alias {email} war erfolgreich!",
|
"Creation of alias {email} was successful!": "Erstellen des Alias {email} war erfolgreich!",
|
||||||
"Alias {email} was deleted successfully": "Alias {email} wurde erfolgreich gelöscht",
|
"Alias {email} was deleted successfully": "Alias {email} wurde erfolgreich gelöscht",
|
||||||
|
|||||||
@ -5,6 +5,7 @@ from .alias.create import AliasCreate
|
|||||||
from .alias.delete import AliasDelete
|
from .alias.delete import AliasDelete
|
||||||
from .alias.detail import AliasDetail
|
from .alias.detail import AliasDetail
|
||||||
from .alias.edit_note import AliasEditNote
|
from .alias.edit_note import AliasEditNote
|
||||||
|
from .alias.toggle_can_receive import AliasToggleCanReceive
|
||||||
from .alias.toggle_enabled import AliasToggleEnabled
|
from .alias.toggle_enabled import AliasToggleEnabled
|
||||||
from .favicon import Favicon
|
from .favicon import Favicon
|
||||||
from .robots import RobotsTXT
|
from .robots import RobotsTXT
|
||||||
@ -15,6 +16,7 @@ from .user.detail import UserDetail
|
|||||||
from .user.edit_note import UserEditNote
|
from .user.edit_note import UserEditNote
|
||||||
from .user.list import UserList
|
from .user.list import UserList
|
||||||
from .user.toggle_admin import UserToggleAdmin
|
from .user.toggle_admin import UserToggleAdmin
|
||||||
|
from .user.toggle_can_receive import UserToggleCanReceive
|
||||||
from .user.toggle_enabled import UserToggleEnabled
|
from .user.toggle_enabled import UserToggleEnabled
|
||||||
|
|
||||||
|
|
||||||
@ -36,6 +38,11 @@ def init_routes(app):
|
|||||||
"user-toggle-enabled",
|
"user-toggle-enabled",
|
||||||
UserToggleEnabled.as_view(),
|
UserToggleEnabled.as_view(),
|
||||||
)
|
)
|
||||||
|
app.add_url_rule(
|
||||||
|
"/user/<int:user_id>/toggle-can-receive",
|
||||||
|
"user-toggle-can-receive",
|
||||||
|
UserToggleCanReceive.as_view(),
|
||||||
|
)
|
||||||
app.add_url_rule(
|
app.add_url_rule(
|
||||||
"/user/<int:user_id>/toggle-admin",
|
"/user/<int:user_id>/toggle-admin",
|
||||||
"user-toggle-admin",
|
"user-toggle-admin",
|
||||||
@ -57,6 +64,11 @@ def init_routes(app):
|
|||||||
"alias-toggle-enabled",
|
"alias-toggle-enabled",
|
||||||
AliasToggleEnabled.as_view(),
|
AliasToggleEnabled.as_view(),
|
||||||
)
|
)
|
||||||
|
app.add_url_rule(
|
||||||
|
"/alias/<int:alias_id>/toggle-can-receive",
|
||||||
|
"alias-toggle-can-receive",
|
||||||
|
AliasToggleCanReceive.as_view(),
|
||||||
|
)
|
||||||
|
|
||||||
app.add_url_rule(
|
app.add_url_rule(
|
||||||
"/robots.txt",
|
"/robots.txt",
|
||||||
|
|||||||
@ -38,6 +38,15 @@ class AliasCreate(
|
|||||||
flash(t("Enabled is not set"), category="error")
|
flash(t("Enabled is not set"), category="error")
|
||||||
error = True
|
error = True
|
||||||
|
|
||||||
|
can_receive = self.request.form.get("can_receive")
|
||||||
|
if can_receive == "on":
|
||||||
|
self.can_receive = True
|
||||||
|
elif can_receive is None:
|
||||||
|
self.can_receive = False
|
||||||
|
else:
|
||||||
|
flash(t("Can receive is not set"), category="error")
|
||||||
|
error = True
|
||||||
|
|
||||||
note = self.request.form.get("note", "")
|
note = self.request.form.get("note", "")
|
||||||
if not isinstance(note, str):
|
if not isinstance(note, str):
|
||||||
flash(t("Note must be a string"), category="error")
|
flash(t("Note must be a string"), category="error")
|
||||||
@ -49,7 +58,9 @@ class AliasCreate(
|
|||||||
return # force re-rendering
|
return # force re-rendering
|
||||||
|
|
||||||
try:
|
try:
|
||||||
create_alias(self.email, self.user, self.enabled, self.note)
|
create_alias(
|
||||||
|
self.email, self.user, self.enabled, self.can_receive, self.note
|
||||||
|
)
|
||||||
except EmailAlreadyExists as e:
|
except EmailAlreadyExists as e:
|
||||||
if self.auth_user.is_admin:
|
if self.auth_user.is_admin:
|
||||||
flash(
|
flash(
|
||||||
@ -68,7 +79,7 @@ class AliasCreate(
|
|||||||
|
|
||||||
def get_context(self):
|
def get_context(self):
|
||||||
context = super().get_context()
|
context = super().get_context()
|
||||||
for key in ("email", "enabled", "note"):
|
for key in ("email", "enabled", "can_receive", "note"):
|
||||||
if hasattr(self, key):
|
if hasattr(self, key):
|
||||||
context[key] = getattr(self, key)
|
context[key] = getattr(self, key)
|
||||||
return context
|
return context
|
||||||
|
|||||||
14
max/routes/alias/toggle_can_receive.py
Normal file
14
max/routes/alias/toggle_can_receive.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
from max.db import update_alias
|
||||||
|
from max.permissions import AllowAdminOrSelf
|
||||||
|
from max.views import BaseView
|
||||||
|
|
||||||
|
from ..base_alias_views import BackToAliasesMixin, FetchAliasMixin
|
||||||
|
|
||||||
|
|
||||||
|
class AliasToggleCanReceive(
|
||||||
|
AllowAdminOrSelf, FetchAliasMixin, BackToAliasesMixin, BaseView
|
||||||
|
):
|
||||||
|
def post(self):
|
||||||
|
update_alias(self.alias.id, can_receive=(not self.alias.can_receive))
|
||||||
|
_, back_url = self.get_back_text_and_url()
|
||||||
|
return self.redirect(back_url)
|
||||||
@ -48,6 +48,15 @@ class UserCreate(AllowAdmin, CheckEmailMixin, BackToUsersMixin, BaseTemplateGetV
|
|||||||
flash(t("Enabled is not set"), category="error")
|
flash(t("Enabled is not set"), category="error")
|
||||||
error = True
|
error = True
|
||||||
|
|
||||||
|
can_receive = self.request.form.get("can_receive")
|
||||||
|
if can_receive == "on":
|
||||||
|
self.can_receive = True
|
||||||
|
elif can_receive is None:
|
||||||
|
self.can_receive = False
|
||||||
|
else:
|
||||||
|
flash(t("Can receive is not set"), category="error")
|
||||||
|
error = True
|
||||||
|
|
||||||
is_admin = self.request.form.get("is_admin")
|
is_admin = self.request.form.get("is_admin")
|
||||||
if is_admin == "on":
|
if is_admin == "on":
|
||||||
self.is_admin = True
|
self.is_admin = True
|
||||||
|
|||||||
12
max/routes/user/toggle_can_receive.py
Normal file
12
max/routes/user/toggle_can_receive.py
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
from max.db import update_user
|
||||||
|
from max.permissions import AllowAdmin
|
||||||
|
from max.views import BaseView
|
||||||
|
|
||||||
|
from ..base_user_views import BackToUsersMixin, FetchUserMixin
|
||||||
|
|
||||||
|
|
||||||
|
class UserToggleCanReceive(AllowAdmin, FetchUserMixin, BackToUsersMixin, BaseView):
|
||||||
|
def post(self):
|
||||||
|
update_user(self.user.id, can_receive=(not self.user.can_receive))
|
||||||
|
_, back_url = self.get_back_text_and_url()
|
||||||
|
return self.redirect(back_url)
|
||||||
@ -144,14 +144,21 @@ form {
|
|||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
}
|
}
|
||||||
.detail b {
|
.detail b {
|
||||||
width: 4.5em;
|
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
}
|
}
|
||||||
|
.detail .note a {
|
||||||
|
margin-right: 1em;
|
||||||
|
margin-left: 1em;
|
||||||
|
vertical-align: top;
|
||||||
|
}
|
||||||
.detail .note b {
|
.detail .note b {
|
||||||
|
margin-right: 1em;
|
||||||
|
margin-top: 0.5em;
|
||||||
vertical-align: top;
|
vertical-align: top;
|
||||||
}
|
}
|
||||||
.detail .note div {
|
.detail .note div {
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
|
margin-top: 0.5em;
|
||||||
}
|
}
|
||||||
.detail form {
|
.detail form {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
@ -174,6 +181,9 @@ form {
|
|||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-bottom: 0.5em;
|
margin-bottom: 0.5em;
|
||||||
}
|
}
|
||||||
|
.connection-properties .indent {
|
||||||
|
margin-left: 1.5em;
|
||||||
|
}
|
||||||
|
|
||||||
.checkbox {
|
.checkbox {
|
||||||
padding: 8px;
|
padding: 8px;
|
||||||
|
|||||||
@ -17,6 +17,13 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="pure-controls checkbox">
|
||||||
|
<label for="can_receive">
|
||||||
|
<input id="can_receive" type="checkbox" name="can_receive" {% if can_receive %}checked{% endif %}>
|
||||||
|
{{ t("Can receive emails") }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="pure-control-group">
|
<div class="pure-control-group">
|
||||||
<label for="note">{{ t("Note") }}</label>
|
<label for="note">{{ t("Note") }}</label>
|
||||||
<textarea id="note" name="note" form="form">{% if note is defined %}{{ note }}{% endif %}</textarea>
|
<textarea id="note" name="note" form="form">{% if note is defined %}{{ note }}{% endif %}</textarea>
|
||||||
|
|||||||
@ -8,13 +8,19 @@
|
|||||||
<div>
|
<div>
|
||||||
<b>{{ t("Enabled") }}:</b>
|
<b>{{ t("Enabled") }}:</b>
|
||||||
{{ macros.checkbox(alias, "enabled", url_for('alias-toggle-enabled', alias_id=alias.id, return='detail')) }}
|
{{ macros.checkbox(alias, "enabled", url_for('alias-toggle-enabled', alias_id=alias.id, return='detail')) }}
|
||||||
</div><div class="note">
|
</div>
|
||||||
|
<div>
|
||||||
|
<b>{{ t("Can receive emails") }}:</b>
|
||||||
|
{{ macros.checkbox(alias, "can_receive", url_for('alias-toggle-can-receive', alias_id=alias.id, return='detail')) }}
|
||||||
|
</div>
|
||||||
|
<div class="note">
|
||||||
<b>{{ t("Note") }}:</b><div>{{ macros.format_note(alias) }}</div>
|
<b>{{ t("Note") }}:</b><div>{{ macros.format_note(alias) }}</div>
|
||||||
<a href="{{ url_for('alias-edit-note', alias_id=alias.id, return='detail') }}" class="button-small pure-button optional">
|
<a href="{{ url_for('alias-edit-note', alias_id=alias.id, return='detail') }}" class="button-small pure-button optional">
|
||||||
<i class="fa fa-pen"></i>
|
<i class="fa fa-pen"></i>
|
||||||
{{ t("Edit") }}
|
{{ t("Edit") }}
|
||||||
</a>
|
</a>
|
||||||
</div><div>
|
</div>
|
||||||
|
<div>
|
||||||
<a href="{{ url_for('alias-delete', alias_id=alias.id, return='detail') }}" class="button-small button-error pure-button">
|
<a href="{{ url_for('alias-delete', alias_id=alias.id, return='detail') }}" class="button-small button-error pure-button">
|
||||||
<i class="fa fa-trash"></i>
|
<i class="fa fa-trash"></i>
|
||||||
{{ t("Delete") }}
|
{{ t("Delete") }}
|
||||||
|
|||||||
@ -27,6 +27,13 @@
|
|||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="pure-controls checkbox">
|
||||||
|
<label for="can_receive">
|
||||||
|
<input id="can_receive" type="checkbox" name="can_receive" {% if can_receive %}checked{% endif %}>
|
||||||
|
{{ t("Can receive emails") }}
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="pure-controls checkbox">
|
<div class="pure-controls checkbox">
|
||||||
<label for="is_admin">
|
<label for="is_admin">
|
||||||
<input id="is_admin" type="checkbox" name="is_admin" {% if is_admin %}checked{% endif %}>
|
<input id="is_admin" type="checkbox" name="is_admin" {% if is_admin %}checked{% endif %}>
|
||||||
|
|||||||
@ -20,6 +20,10 @@
|
|||||||
<b>{{ t("Enabled") }}:</b>
|
<b>{{ t("Enabled") }}:</b>
|
||||||
{{ macros.checkbox(user, "enabled", url_for('user-toggle-enabled', user_id=user.id, return='detail')) }}
|
{{ macros.checkbox(user, "enabled", url_for('user-toggle-enabled', user_id=user.id, return='detail')) }}
|
||||||
</div>
|
</div>
|
||||||
|
<div>
|
||||||
|
<b>{{ t("Can receive emails") }}:</b>
|
||||||
|
{{ macros.checkbox(user, "can_receive", url_for('user-toggle-can-receive', user_id=user.id, return='detail')) }}
|
||||||
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<b>{{ t("Admin") }}:</b>
|
<b>{{ t("Admin") }}:</b>
|
||||||
{{ macros.checkbox(user, "is_admin", url_for('user-toggle-admin', user_id=user.id, return='detail')) }}
|
{{ macros.checkbox(user, "is_admin", url_for('user-toggle-admin', user_id=user.id, return='detail')) }}
|
||||||
@ -53,10 +57,14 @@
|
|||||||
|
|
||||||
<details class="connection-properties">
|
<details class="connection-properties">
|
||||||
<summary>{{ t("Email connection properties") }}</summary>
|
<summary>{{ t("Email connection properties") }}</summary>
|
||||||
<p>IMAP: mail.finn.st, Port: 993</p>
|
<p>IMAP: finn.st, Port 993</p>
|
||||||
<p>username: {{ user.email }}</p>
|
<p class="indent">Username: {{ user.email }}</p>
|
||||||
<p>Connection security: SSL/TLS</p>
|
<p class="indent">Connection security: SSL/TLS</p>
|
||||||
<p>Authentication method: password</p>
|
<p class="indent">Authentication method: password</p>
|
||||||
|
<p>SMTP: finn.st, Port 587</p>
|
||||||
|
<p class="indent">Username: {{ user.email }}</p>
|
||||||
|
<p class="indent">Connection security: STARTTLS</p>
|
||||||
|
<p class="indent">Authentication method: password</p>
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
{% if aliases|length > 0 %}
|
{% if aliases|length > 0 %}
|
||||||
@ -66,6 +74,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>{{ t("Email") }}</th>
|
<th>{{ t("Email") }}</th>
|
||||||
<th>{{ t("Enabled") }}</th>
|
<th>{{ t("Enabled") }}</th>
|
||||||
|
<th>{{ t("Can receive emails") }}</th>
|
||||||
<th>{{ t("Note") }}</th>
|
<th>{{ t("Note") }}</th>
|
||||||
<th class="optional">{{ t("Actions") }}</th>
|
<th class="optional">{{ t("Actions") }}</th>
|
||||||
</tr>
|
</tr>
|
||||||
@ -80,6 +89,9 @@
|
|||||||
<td>
|
<td>
|
||||||
{{ macros.checkbox(alias, "enabled", url_for('alias-toggle-enabled', alias_id=alias.id)) }}
|
{{ macros.checkbox(alias, "enabled", url_for('alias-toggle-enabled', alias_id=alias.id)) }}
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ macros.checkbox(alias, "can_receive", url_for('alias-toggle-can-receive', alias_id=alias.id)) }}
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ macros.format_note(alias) }}
|
{{ macros.format_note(alias) }}
|
||||||
<a href="{{ url_for('alias-edit-note', alias_id=alias.id) }}" class="button-small pure-button optional">
|
<a href="{{ url_for('alias-edit-note', alias_id=alias.id) }}" class="button-small pure-button optional">
|
||||||
|
|||||||
@ -20,6 +20,7 @@
|
|||||||
<tr>
|
<tr>
|
||||||
<th>{{ t("Email") }}</th>
|
<th>{{ t("Email") }}</th>
|
||||||
<th>{{ t("Enabled") }}</th>
|
<th>{{ t("Enabled") }}</th>
|
||||||
|
<th>{{ t("Can receive emails") }}</th>
|
||||||
<th>{{ t("Admin") }}</th>
|
<th>{{ t("Admin") }}</th>
|
||||||
<th>{{ t("Note") }}</th>
|
<th>{{ t("Note") }}</th>
|
||||||
<th class="optional">{{ t("Actions") }}</th>
|
<th class="optional">{{ t("Actions") }}</th>
|
||||||
@ -35,6 +36,9 @@
|
|||||||
<td>
|
<td>
|
||||||
{{ macros.checkbox(user, "enabled", url_for('user-toggle-enabled', user_id=user.id)) }}
|
{{ macros.checkbox(user, "enabled", url_for('user-toggle-enabled', user_id=user.id)) }}
|
||||||
</td>
|
</td>
|
||||||
|
<td>
|
||||||
|
{{ macros.checkbox(user, "can_receive", url_for('user-toggle-can-receive', user_id=user.id)) }}
|
||||||
|
</td>
|
||||||
<td>
|
<td>
|
||||||
{{ macros.checkbox(user, "is_admin", url_for('user-toggle-admin', user_id=user.id)) }}
|
{{ macros.checkbox(user, "is_admin", url_for('user-toggle-admin', user_id=user.id)) }}
|
||||||
</td>
|
</td>
|
||||||
|
|||||||
2
scripts/psql.sh
Executable file
2
scripts/psql.sh
Executable file
@ -0,0 +1,2 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
PGPASSWORD="$PGSQL_PASSWORD" psql -h "$PGSQL_HOST" -p "$PGSQL_PORT" -U "$PGSQL_USER" -d "$PGSQL_NAME"
|
||||||
Loading…
x
Reference in New Issue
Block a user