Skip to content
GitLab
Menu
Projects
Groups
Snippets
/
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
Menu
Open sidebar
Martin Mareš
Postal Owl
Commits
def763d6
Commit
def763d6
authored
Sep 28, 2021
by
Martin Mareš
Browse files
If a user has multiple e-mails in CAS, pick one of them
We prefer local UK addresses.
parent
72e5ab00
Changes
3
Hide whitespace changes
Inline
Side-by-side
db.ddl
View file @
def763d6
...
@@ -6,7 +6,6 @@ CREATE TABLE owl_users (
...
@@ -6,7 +6,6 @@ CREATE TABLE owl_users (
auth_token varchar(64) UNIQUE DEFAULT NULL, -- this is called "access key" in UI
auth_token varchar(64) UNIQUE DEFAULT NULL, -- this is called "access key" in UI
full_name varchar(255) NOT NULL,
full_name varchar(255) NOT NULL,
email varchar(255) DEFAULT NULL,
email varchar(255) DEFAULT NULL,
-- we allow CAS's format "{email1,email2,...}"
created timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
created timestamp with time zone NOT NULL DEFAULT CURRENT_TIMESTAMP,
is_admin boolean NOT NULL DEFAULT false,
is_admin boolean NOT NULL DEFAULT false,
notify boolean NOT NULL DEFAULT false,
notify boolean NOT NULL DEFAULT false,
...
...
owl.py
View file @
def763d6
...
@@ -1033,7 +1033,7 @@ def user_settings():
...
@@ -1033,7 +1033,7 @@ def user_settings():
form
.
notify_self
.
data
=
user
.
notify_self
form
.
notify_self
.
data
=
user
.
notify_self
form
.
inline_att
.
data
=
user
.
inline_att
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 ###
### Administration ###
...
@@ -1347,17 +1347,37 @@ def cas_login():
...
@@ -1347,17 +1347,37 @@ def cas_login():
return
redirect
(
next
)
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
):
def
session_from_cas
(
user
,
attrs
):
db_query
(
"SELECT * FROM owl_users WHERE ukco=%s"
,
(
user
,))
db_query
(
"SELECT * FROM owl_users WHERE ukco=%s"
,
(
user
,))
row
=
db
.
fetchone
()
row
=
db
.
fetchone
()
if
row
:
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
)
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
:
else
:
email
=
primary_cas_email
(
attrs
[
'mail'
])
db_query
(
"""
db_query
(
"""
INSERT INTO owl_users(ukco, full_name, email)
INSERT INTO owl_users(ukco, full_name, email)
VALUES (%s, %s, %s)
VALUES (%s, %s, %s)
RETURNING uid, ukco, full_name, email, is_admin, inline_att
RETURNING uid, ukco, full_name, email, is_admin, inline_att
"""
,
(
user
,
attrs
[
'cn'
],
attrs
[
'
mail
'
]
))
"""
,
(
user
,
attrs
[
'cn'
],
e
mail
))
row
=
db
.
fetchone
()
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
)
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
()
db_connection
.
commit
()
...
@@ -1562,6 +1582,25 @@ def cli_add_teacher(course_ident, teacher):
...
@@ -1562,6 +1582,25 @@ def cli_add_teacher(course_ident, teacher):
db_connection
.
commit
()
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 ###
### Sending notifications ###
...
@@ -1626,26 +1665,20 @@ def send_notify_post(post):
...
@@ -1626,26 +1665,20 @@ def send_notify_post(post):
app
.
logger
.
info
(
f
"E-mail: not sending self-notify to uid=
{
dest
.
uid
}
"
)
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
):
def
send_notify_to_dest
(
post
,
topic
,
course
,
author
,
target
,
dest
):
emails
=
parse_emails
(
dest
.
email
)
if
'MAIL_FROM'
not
in
app
.
config
:
if
'MAIL_FROM'
not
in
app
.
config
:
app
.
logger
.
info
(
'Not sending: MAIL_FROM not defined'
)
app
.
logger
.
info
(
'Not sending: MAIL_FROM not defined'
)
return
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
=
email
.
message
.
EmailMessage
()
msg
[
'From'
]
=
email
.
headerregistry
.
Address
(
display_name
=
author
.
full_name
+
" via Owl"
,
addr_spec
=
app
.
config
[
'MAIL_FROM'
])
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
email
s
]
msg
[
'To'
]
=
email
.
headerregistry
.
Address
(
display_name
=
dest
.
full_name
,
addr_spec
=
dest
.
email
)
msg
[
'Subject'
]
=
f
'Owl:
{
topic
.
title
}
'
msg
[
'Subject'
]
=
f
'Owl:
{
topic
.
title
}
'
msg
[
'Date'
]
=
(
post
.
modified
or
post
.
created
).
astimezone
()
msg
[
'Date'
]
=
(
post
.
modified
or
post
.
created
).
astimezone
()
if
'MAIL_REFERENCES'
in
app
.
config
:
if
'MAIL_REFERENCES'
in
app
.
config
:
...
@@ -1690,7 +1723,8 @@ def send_notify_to_dest(post, topic, course, author, target, dest):
...
@@ -1690,7 +1723,8 @@ def send_notify_to_dest(post, topic, course, author, target, dest):
"/usr/sbin/sendmail"
,
"/usr/sbin/sendmail"
,
"-oi"
,
"-oi"
,
"-f"
,
app
.
config
[
'MAIL_FROM'
],
"-f"
,
app
.
config
[
'MAIL_FROM'
],
]
+
emails
,
stdin
=
subprocess
.
PIPE
)
dest
.
email
,
],
stdin
=
subprocess
.
PIPE
)
sm
.
communicate
(
msg
.
as_bytes
())
sm
.
communicate
(
msg
.
as_bytes
())
if
sm
.
returncode
!=
0
:
if
sm
.
returncode
!=
0
:
app
.
logger
.
error
(
"Sendmail failed with return code %d"
,
sm
.
returncode
)
app
.
logger
.
error
(
"Sendmail failed with return code %d"
,
sm
.
returncode
)
...
...
templates/settings.html
View file @
def763d6
...
@@ -6,7 +6,7 @@
...
@@ -6,7 +6,7 @@
{{ form.csrf_token }}
{{ form.csrf_token }}
<table
class=
settings
>
<table
class=
settings
>
<tr><td>
Name:
<td>
{{ user.full_name }}
<tr><td>
Name:
<td>
{{ user.full_name }}
<tr><td>
E-mail:
<td>
{{
"
<br>
".join(
email
s)
}}
<tr><td>
E-mail:
<td>
{{
user.
email }}
<tr><td>
Notify by e-mail:
<td>
{{ form.notify() }}
<tr><td>
Notify by e-mail:
<td>
{{ form.notify() }}
<tr><td>
Notify on own posts:
<td>
{{ form.notify_self() }}
<tr><td>
Notify on own posts:
<td>
{{ form.notify_self() }}
<tr><td>
Show PDF attachments inline:
<td>
{{ form.inline_att() }}
<tr><td>
Show PDF attachments inline:
<td>
{{ form.inline_att() }}
...
...
Write
Preview
Supports
Markdown
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment