Commit def763d6 authored by Martin Mareš's avatar Martin Mareš
Browse files

If a user has multiple e-mails in CAS, pick one of them

We prefer local UK addresses.
parent 72e5ab00
......@@ -6,7 +6,6 @@ CREATE TABLE owl_users (
auth_token varchar(64) UNIQUE DEFAULT NULL, -- this is called "access key" in UI
full_name varchar(255) NOT NULL,
email varchar(255) DEFAULT NULL,
-- we allow CAS's format "{email1,email2,...}"
created timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_admin boolean NOT NULL DEFAULT false,
notify boolean NOT NULL DEFAULT false,
......
......@@ -1033,7 +1033,7 @@ def user_settings():
form.notify_self.data = user.notify_self
form.inline_att.data = user.inline_att
return render_template('settings.html', form=form, user=user, emails=parse_emails(user.email))
return render_template('settings.html', form=form, user=user)
### Administration ###
......@@ -1347,17 +1347,37 @@ def cas_login():
return redirect(next)
def parse_cas_emails(raw_email):
if raw_email[0] == '{' and raw_email[-1] == '}':
# Strange CAS encoding of multiple e-mail addresses
return raw_email[1:-1].split(',')
else:
return [raw_email]
def primary_cas_email(raw_email):
emails = parse_cas_emails(raw_email)
if not emails:
return None
uk = [e for e in emails if e.endswith('.cuni.cz')]
if uk:
return uk[0]
else:
return emails[0]
def session_from_cas(user, attrs):
db_query("SELECT * FROM owl_users WHERE ukco=%s", (user,))
row = db.fetchone()
if row:
app.logger.info('Logged in user: uid=%s, ukco=%s, cn=%s, mail=%s, admin=%s', row.uid, row.ukco, row.full_name, row.email, row.is_admin)
else:
email = primary_cas_email(attrs['mail'])
db_query("""
INSERT INTO owl_users(ukco, full_name, email)
VALUES (%s, %s, %s)
RETURNING uid, ukco, full_name, email, is_admin, inline_att
""", (user, attrs['cn'], attrs['mail']))
""", (user, attrs['cn'], email))
row = db.fetchone()
app.logger.info('Created new user: uid=%s, ukco=%s, cn=%s, mail=%s', row.uid, row.ukco, row.full_name, row.email)
db_connection.commit()
......@@ -1562,6 +1582,25 @@ def cli_add_teacher(course_ident, teacher):
db_connection.commit()
@app.cli.command("convert-emails")
def cli_convert_emails():
"""Convert up e-mail addresses in the database from old SIS format."""
db_query("""
SELECT *
FROM owl_users
WHERE email LIKE '%%{%%'
""")
users = db.fetchall()
for u in users:
primary = primary_cas_email(u.email)
print(u.uid, u.full_name, u.email, '->', primary)
db_query("UPDATE owl_users SET email=%s WHERE uid=%s", (primary, u.uid))
db_connection.commit()
### Sending notifications ###
......@@ -1626,26 +1665,20 @@ def send_notify_post(post):
app.logger.info(f"E-mail: not sending self-notify to uid={dest.uid}")
def parse_emails(raw_email):
if raw_email[0] == '{' and raw_email[-1] == '}':
# Strange CAS encoding of multiple e-mail addresses
return raw_email[1:-1].split(',')
else:
return [raw_email]
def send_notify_to_dest(post, topic, course, author, target, dest):
emails = parse_emails(dest.email)
if 'MAIL_FROM' not in app.config:
app.logger.info('Not sending: MAIL_FROM not defined')
return
app.logger.info(f"E-mail: uid={dest.uid} emails={emails}")
if not dest.email:
app.logger.info(f"E-mail: uid={dest.uid} has no address")
return
app.logger.info(f"E-mail: uid={dest.uid} email={dest.email}")
msg = email.message.EmailMessage()
msg['From'] = email.headerregistry.Address(display_name=author.full_name + " via Owl", addr_spec=app.config['MAIL_FROM'])
msg['To'] = [ email.headerregistry.Address(display_name=dest.full_name, addr_spec=e) for e in emails ]
msg['To'] = email.headerregistry.Address(display_name=dest.full_name, addr_spec=dest.email)
msg['Subject'] = f'Owl: {topic.title}'
msg['Date'] = (post.modified or post.created).astimezone()
if 'MAIL_REFERENCES' in app.config:
......@@ -1690,7 +1723,8 @@ def send_notify_to_dest(post, topic, course, author, target, dest):
"/usr/sbin/sendmail",
"-oi",
"-f", app.config['MAIL_FROM'],
] + emails, stdin=subprocess.PIPE)
dest.email,
], stdin=subprocess.PIPE)
sm.communicate(msg.as_bytes())
if sm.returncode != 0:
app.logger.error("Sendmail failed with return code %d", sm.returncode)
......
......@@ -6,7 +6,7 @@
{{ form.csrf_token }}
<table class=settings>
<tr><td>Name:<td>{{ user.full_name }}
<tr><td>E-mail:<td>{{ "<br>".join(emails) }}
<tr><td>E-mail:<td>{{ user.email }}
<tr><td>Notify by e-mail:<td>{{ form.notify() }}
<tr><td>Notify on own posts:<td>{{ form.notify_self() }}
<tr><td>Show PDF attachments inline:<td>{{ form.inline_att() }}
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment