Skip to content

Commit

Permalink
Allow disabling registration, treat admins like owners in single-tree…
Browse files Browse the repository at this point in the history
… setup (#484)

* Allow disabling registration;
Do not disable registration in single-tree setup if only admin exists

* Send new user e-mail also to admins for single-tree
  • Loading branch information
DavidMStraub authored Feb 4, 2024
1 parent 1b058f9 commit 5fb71e9
Show file tree
Hide file tree
Showing 4 changed files with 38 additions and 9 deletions.
23 changes: 21 additions & 2 deletions gramps_webapi/api/resources/user.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

import datetime
from gettext import gettext as _
from typing import Tuple
from typing import Optional, Tuple

from flask import abort, current_app, jsonify, render_template, request
from flask_jwt_extended import create_access_token, get_jwt, get_jwt_identity
Expand Down Expand Up @@ -296,6 +296,22 @@ def delete(self, user_name: str):
class UserRegisterResource(Resource):
"""Resource for registering a new user."""

def _is_disabled(self, tree: Optional[str]) -> bool:
"""Check if the registration is disabled."""
if current_app.config["REGISTRATION_DISABLED"]:
return True
# check if there are tree owners or, in a single-tree setup,
# tree admins
if current_app.config["TREE"] == TREE_MULTI:
roles = (ROLE_OWNER,)
else:
roles = (ROLE_OWNER, ROLE_ADMIN)
if get_number_users(tree=tree, roles=roles) == 0:
# no users authorized to enable new accounts:
# registration disabled
return True
return False

@limiter.limit("1/second")
@use_args(
{
Expand All @@ -315,7 +331,7 @@ def post(self, args, user_name: str):
# if multi-tree is enabled, tree is required
abort_with_message(422, "tree is required")
# do not allow registration if no tree owner account exists!
if get_number_users(tree=args.get("tree"), roles=(ROLE_OWNER,)) == 0:
if self._is_disabled(tree=args.get("tree")):
abort_with_message(405, "Registration is disabled")
if (
"tree" in args
Expand Down Expand Up @@ -542,12 +558,15 @@ def get(self):
# otherwise it has been confirmed already
modify_user(name=username, role=ROLE_DISABLED)
tree = get_tree_from_jwt()
is_multi = current_app.config["TREE"] == TREE_MULTI
run_task(
send_email_new_user,
username=username,
fullname=current_details.get("full_name", ""),
email=claims["email"],
tree=tree,
# for single-tree setups, send e-mail also to admins
include_admins=not is_multi,
)
title = _("E-mail address confirmation")
message = _("Thank you for confirming your e-mail address.")
Expand Down
6 changes: 4 additions & 2 deletions gramps_webapi/api/tasks.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,14 +80,16 @@ def send_email_confirm_email(email: str, token: str):


@shared_task()
def send_email_new_user(username: str, fullname: str, email: str, tree: str):
def send_email_new_user(
username: str, fullname: str, email: str, tree: str, include_admins: bool
):
"""Send an email to owners to notify of a new registered user."""
base_url = get_config("BASE_URL").rstrip("/")
body = email_new_user(
base_url=base_url, username=username, fullname=fullname, email=email
)
subject = _("New registered user")
emails = get_owner_emails(tree=tree)
emails = get_owner_emails(tree=tree, include_admins=include_admins)
if emails:
send_email(subject=subject, body=body, to=emails)

Expand Down
17 changes: 12 additions & 5 deletions gramps_webapi/auth/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
from sqlalchemy.sql.functions import coalesce

from ..const import DB_CONFIG_ALLOWED_KEYS
from .const import PERMISSIONS, ROLE_OWNER
from .const import PERMISSIONS, ROLE_ADMIN, ROLE_OWNER
from .passwords import hash_password, verify_password
from .sql_guid import GUID

Expand Down Expand Up @@ -239,11 +239,18 @@ def get_permissions(username: str) -> Set[str]:
return PERMISSIONS[user.role]


def get_owner_emails(tree: str) -> List[str]:
"""Get e-mail addresses of all tree owners."""
def get_owner_emails(tree: str, include_admins: bool = False) -> List[str]:
"""Get e-mail addresses of all tree owners (and optionally include site admins)."""
query = user_db.session.query(User) # pylint: disable=no-member
owners = query.filter_by(tree=tree, role=ROLE_OWNER).all()
return [user.email for user in owners if user.email]
if include_admins:
users = (
query.filter_by(tree=tree)
.filter(sa.or_(User.role == ROLE_OWNER, User.role == ROLE_ADMIN))
.all()
)
else:
users = query.filter_by(tree=tree, role=ROLE_OWNER).all()
return [user.email for user in users if user.email]


def get_number_users(
Expand Down
1 change: 1 addition & 0 deletions gramps_webapi/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ class DefaultConfig(object):
EXPORT_DIR = str(Path.cwd() / "export_cache")
NEW_DB_BACKEND = "sqlite"
RATE_LIMIT_MEDIA_ARCHIVE = "1 per day"
REGISTRATION_DISABLED = False


class DefaultConfigJWT(object):
Expand Down

0 comments on commit 5fb71e9

Please sign in to comment.