Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
R
RWTH.nb
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Iterations
Requirements
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Locked files
Build
Pipelines
Jobs
Pipeline schedules
Test cases
Artifacts
Deploy
Releases
Package registry
Container registry
Model registry
Operate
Environments
Terraform modules
Monitor
Incidents
Service Desk
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Code review analytics
Issue analytics
Insights
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Terms and privacy
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
RWTHjupyter
RWTH.nb
Commits
d2229fbc
Commit
d2229fbc
authored
4 years ago
by
Hafiz Emin Kosar
Browse files
Options
Downloads
Patches
Plain Diff
- split RWTHFeedback class into different sub-classes for better readability
parent
544ca3b6
No related branches found
No related tags found
1 merge request
!10
- major changes in feedback
Changes
2
Show whitespace changes
Inline
Side-by-side
Showing
2 changed files
docs/source/examples/RWTH Misc.ipynb
+2
-2
2 additions, 2 deletions
docs/source/examples/RWTH Misc.ipynb
rwth_nb/misc/feedback.py
+203
-194
203 additions, 194 deletions
rwth_nb/misc/feedback.py
with
205 additions
and
196 deletions
docs/source/examples/RWTH Misc.ipynb
+
2
−
2
View file @
d2229fbc
...
...
@@ -50,7 +50,7 @@
"source": [
"import rwth_nb.misc.feedback as rwth_feedback\n",
"\n",
"mail_to = \"
hafiz.emin.kosar@gmail.com
\" # send feedback via mail\n",
"mail_to = \"
example@rwth-aachen.de
\" # send feedback via mail\n",
"feedback_name = rwth_feedback.get_notebook_name() # get name of notebook automatically\n",
"rwth_feedback.RWTHFeedback(feedback_name, [\n",
" {'id': 'likes', 'type': 'free-text-required', 'label': 'Das war gut:'}, \n",
...
...
%% Cell type:markdown id: tags:
# Miscellaneous
1.
[
Feedback
](
#Feedback
)
2.
[
Transforms
](
#Transforms
)
1.
[
Fourier Transform
](
#Fourier-Transform
)
2.
[
Laplace Transform
](
#Laplace-Transform
)
3.
[
$z$-Transform
](
#$z$-Transform
)
%% Cell type:markdown id: tags:
---
%% Cell type:markdown id: tags:
## Feedback
A feedback form can be created for participants to rate the course.
Use
`RWTHFeedback`
class in
`rwth_nb.misc.rwth_feedback`
The arguments of the class that is created are depending on which environment the feedback form is intended to be used.
%% Cell type:markdown id: tags:
### Offline
In this method, the feedback is sent via mail to a receiver.
%% Cell type:code id: tags:
```
python
import
rwth_nb.misc.feedback
as
rwth_feedback
mail_to
=
"
hafiz.emin.kosar@gmail.com
"
# send feedback via mail
mail_to
=
"
example@rwth-aachen.de
"
# send feedback via mail
feedback_name
=
rwth_feedback
.
get_notebook_name
()
# get name of notebook automatically
rwth_feedback
.
RWTHFeedback
(
feedback_name
,
[
{
'
id
'
:
'
likes
'
,
'
type
'
:
'
free-text-required
'
,
'
label
'
:
'
Das war gut:
'
},
{
'
id
'
:
'
dislikes
'
,
'
type
'
:
'
free-text-required
'
,
'
label
'
:
'
Das könnte verbessert werden:
'
},
{
'
id
'
:
'
misc
'
,
'
type
'
:
'
free-text
'
,
'
label
'
:
'
Was ich sonst noch sagen möchte:
'
},
{
'
id
'
:
'
learning
'
,
'
type
'
:
'
scale
'
,
'
label
'
:
'
Ich habe das Gefühl etwas gelernt zu haben.
'
},
{
'
id
'
:
'
supervision
'
,
'
type
'
:
'
scale
'
,
'
label
'
:
'
Die Betreuung des Versuchs war gut.
'
},
{
'
id
'
:
'
script
'
,
'
type
'
:
'
scale
'
,
'
label
'
:
'
Die Versuchsunterlagen sind verständlich.
'
},
],
feedback_path
=
'
feedback.json
'
,
lang
=
'
de
'
,
mail_to
=
mail_to
);
```
%% Cell type:markdown id: tags:
### _RWTHjupyter_ Cluster
%% Cell type:markdown id: tags:
This method uses _RWTHJupyters_ submission service.
%% Cell type:code id: tags:
```
python
import
rwth_nb.misc.feedback
as
rwth_feedback
feedback_name
=
rwth_feedback
.
get_notebook_name
()
# get name of notebook automatically
rwth_feedback
.
RWTHFeedback
(
feedback_name
,
[
{
'
id
'
:
'
likes
'
,
'
type
'
:
'
free-text-required
'
,
'
label
'
:
'
Das war gut:
'
},
{
'
id
'
:
'
dislikes
'
,
'
type
'
:
'
free-text-required
'
,
'
label
'
:
'
Das könnte verbessert werden:
'
},
{
'
id
'
:
'
misc
'
,
'
type
'
:
'
free-text
'
,
'
label
'
:
'
Was ich sonst noch sagen möchte:
'
},
{
'
id
'
:
'
learning
'
,
'
type
'
:
'
scale
'
,
'
label
'
:
'
Ich habe das Gefühl etwas gelernt zu haben.
'
},
{
'
id
'
:
'
supervision
'
,
'
type
'
:
'
scale
'
,
'
label
'
:
'
Die Betreuung des Versuchs war gut.
'
},
{
'
id
'
:
'
script
'
,
'
type
'
:
'
scale
'
,
'
label
'
:
'
Die Versuchsunterlagen sind verständlich.
'
},
],
realm
=
"
feedback_gdet3
"
);
```
%% Cell type:markdown id: tags:
---
%% Cell type:markdown id: tags:
## Transforms
Following transforms are defined in
`rwth_nb.misc.transforms`
:
-
[
Fourier Transform
](
#Fourier-Transform
)
-
[
Laplace Transform
](
#Laplace-Transform
)
-
[
$z$-Transform
](
#$z$-Transform
)
*Note that plotting basics are described in [RWTH Plots](RWTH%20Plots.ipynb).*
%% Cell type:markdown id: tags:
### Fourier Transform
```
dft(s, fs, NFFT)```
%% Cell type:code id: tags:
```
python
import matplotlib.pyplot as plt
import numpy as np
import rwth_nb.plots.mpl_decorations as rwth_plots
import rwth_nb.misc.transforms as rwth_transforms
# Time Domain
fs = 44100 # very high sampling rate assumed, to simulate quasi-continuous time and frequency axis
t = np.linspace(-2.5, 2.5, 5
*
fs)
s = np.sin(2
*np.pi*
500
*
t)
# Fourier Transform
S,f = rwth_transforms.dft(s, fs)
# plots
fig,axs = plt.subplots(2,1,
**
rwth_plots.landscape);
ax = axs[0]; ax.plot(t
*
1000, s);
ax.set_xlabel(r'$
\r
ightarrow t$ [ms]'); ax.set_ylabel(r'$
\u
parrow s(t)$')
ax.set_xlim([-11, 11]); ax.set_ylim([-1.1, 1.19]); rwth_plots.axis(ax);
ax = axs[1]; ax.plot(f, np.abs(S));
ax.set_xlabel(r'$
\r
ightarrow f$ [Hz]'); ax.set_ylabel(r'$
\u
parrow |S(f)|$')
ax.set_xlim([-1100, 1100]); ax.set_ylim([0, 0.65]); rwth_plots.axis(ax);
```
%% Cell type:markdown id: tags:
Inverse Fourier transform
```
idft(S, Ntime, NFF)
```
%% Cell type:code id: tags:
```
python
s2 = rwth_transforms.idft(S, len(s));
fig,ax = plt.subplots(
**
rwth_plots.landscape);
ax.plot(t
*
1000, np.real(s2));
ax.set_xlabel(r'$
\r
ightarrow t$ [ms]'); ax.set_ylabel(r'$
\u
parrow
\m
athcal{F}^{-1}
\{
S(f)
\}
$')
ax.set_xlim([-11, 11]); ax.set_ylim([-1.1, 1.19]); rwth_plots.axis(ax);
```
%% Cell type:markdown id: tags:
### Laplace Transform
Pole-zero plot is explained in [RWTH Plots](RWTH%20Plots.ipynb).
Inverse Laplace Transform
```
ilaplace_ht(t, H0, pp, pz, ord_p, ord_z, roc)
```
```
ilaplace_Hf(f, H0, pp, pz, ord_p, ord_z, dB)
```
%% Cell type:code id: tags:
```
python
fig,axs = plt.subplots(1, 2, figsize=(10, 4))
t = np.linspace(-6, 6, 1024)
f = np.linspace(-6, 6, 1024)
pp = np.array([-2]); pz = np.array([]) # Poles and Zeros
ord_p = np.array([1]); ord_z = np.array([]) # Poles' and Zeros' orders
roc = np.array([-2, np.inf]) # region of convergence
H0 = 1
# Time Domain
s1, t1d , s1d = rwth_transforms.ilaplace_ht(t, H0, pp, pz, ord_p, ord_z, roc)
ax = axs[0]
ax.set_xlabel(r'$
\r
ightarrow t$'); ax.set_ylabel(r'$
\u
parrow s_1(t)$')
rwth_plots.grid(ax); rwth_plots.axis(ax)
ax.set_xlim([-5.5,5.5]); axs[0].set_ylim([-0.1,1.05]);
ax.plot(t, np.real(s1))
rwth_plots.plot_dirac(axs[0], t1d, s1d);
# Frequency Domain
S1f = rwth_transforms.ilaplace_Hf(f, H0, pp, pz, ord_p, ord_z, dB=False)
ax = axs[1]
ax.set_xlabel(r'$
\r
ightarrow f$'); ax.set_ylabel(r'$
\u
parrow S_1(f)$')
rwth_plots.grid(ax); rwth_plots.axis(ax)
ax.set_xlim([-5.5,5.5]); ax.set_ylim([-0.1,0.55]);
ax.plot(f, S1f);
```
%% Cell type:markdown id: tags:
### $z$ Transform
Pole-zero plot is explained in [RWTH Plots](RWTH%20Plots.ipynb).
Inverse $z$ Transform
```
iz_hn(n, H0, pp, pz, ord_p, ord_z, roc)
```
```
iz_Hf(f, H0, pp, pz, ord_p, ord_z, dB)
```
%% Cell type:code id: tags:
```
python
fig,axs = plt.subplots(1, 2, figsize=(10, 4))
n = np.linspace(-6, 6, 13)
f = np.linspace(-6, 6, 1024)
zp = np.array([.5, 2]); zz = np.array([0]) # Poles and Zeros
ord_p = np.array([1, 1]); ord_z = np.array([1]) # Poles' and Zeros' orders
roc = np.array([.5, 2]) # region of convergence
H0 = -3/2
# Time Domain
s1= rwth_transforms.iz_hn(n, H0, zp, zz, ord_p, ord_z, roc)
ax = axs[0]
ax.set_xlabel(r'$
\r
ightarrow n$'); ax.set_ylabel(r'$
\u
parrow s_1(n)$')
rwth_plots.grid(ax); rwth_plots.axis(ax)
ax.set_xlim([-5.5,5.5]); axs[0].set_ylim([-0.1,1.05]);
rwth_plots.stem(axs[0], n, s1);
# Frequency Domain
S1f = rwth_transforms.iz_Hf(f, H0, zp, zz, ord_p, ord_z, dB=False)
ax = axs[1]
ax.set_xlabel(r'$
\r
ightarrow f$'); ax.set_ylabel(r'$
\u
parrow S_1(f)$')
rwth_plots.grid(ax); rwth_plots.axis(ax)
ax.set_xlim([-5.5,5.5]); ax.set_ylim([0.3, 3.1]);
ax.plot(f, S1f);
```
%% Cell type:markdown id: tags:
---
%% Cell type:markdown id: tags:
This code is licensed under the [MIT license](https://opensource.org/licenses/MIT).
...
...
This diff is collapsed.
Click to expand it.
rwth_nb/misc/feedback.py
+
203
−
194
View file @
d2229fbc
...
...
@@ -7,9 +7,32 @@ rwth_colors = rwthcolors.rwth_colors
import
datetime
import
json
import
os
import
hashlib
# for anonymizing the username
import
platform
# for determining operating system
import
subprocess
# for hiding files on Windows
import
hashlib
import
platform
import
subprocess
# Internationalization
feedback_scale_options_de
=
[
'
Stimme voll zu
'
,
'
Ich stimme zu
'
,
'
Keine Meinung
'
,
'
Ich stimme nicht zu
'
,
'
Ich stimme gar nicht zu
'
]
feedback_scale_options_en
=
[
'
Strongly agree
'
,
'
Agree
'
,
'
Neutral
'
,
'
Disagree
'
,
'
Strongly disagree
'
]
feedback_text_de
=
{
"
your-feedback
"
:
"
Feedback ...
"
,
"
send
"
:
"
Abschicken
"
,
"
confirm_send
"
:
"
Abschicken bestätigen.
"
,
"
sent
"
:
"
Das Feedback wurde abgeschickt. Vielen Dank!
"
,
"
required
"
:
"
Pflichtfeld
"
,
"
empty
"
:
"
Bitte ein Feedback eingeben, das abgesendet werden kann.
"
,
"
mailfailure
"
:
"
Die Mail mit dem Feedback konnte nicht versendet werden. Das Feedback wurde lokal abgespeichert.
"
}
feedback_text_en
=
{
"
your-feedback
"
:
"
Your Feedback ...
"
,
"
send
"
:
"
Submit
"
,
"
confirm_send
"
:
"
Confirm submission.
"
,
"
sent
"
:
"
Feedback was submitted. Thank You!
"
,
"
required
"
:
"
Required field
"
,
"
empty
"
:
"
Please fill required fields before submitting.
"
,
"
mailfailure
"
:
"
The mail containing your feedback could not be sent. Your feedback was saved locally.
"
}
def
get_notebook_name
():
...
...
@@ -40,54 +63,21 @@ def get_notebook_name():
return
'
tmp
'
class
RWTHFeedback
:
"""
RWTH Feedback submission class
Use as described in RWTH\ Misc.ipynb
"""
class
RWTHFeedbackBase
:
is_submit_confirmed
=
is_submitted
=
False
# Internationalization
feedback_scale_options_de
=
[
'
Stimme voll zu
'
,
'
Ich stimme zu
'
,
'
Keine Meinung
'
,
'
Ich stimme nicht zu
'
,
'
Ich stimme gar nicht zu
'
]
# Likert-scale
feedback_scale_options_en
=
[
'
Strongly agree
'
,
'
Agree
'
,
'
Neutral
'
,
'
Disagree
'
,
'
Strongly disagree
'
]
feedback_text_de
=
{
"
your-feedback
"
:
"
Feedback ...
"
,
"
send
"
:
"
Abschicken
"
,
"
confirm_send
"
:
"
Abschicken bestätigen.
"
,
"
sent
"
:
"
Das Feedback wurde abgeschickt. Vielen Dank!
"
,
"
required
"
:
"
Pflichtfeld
"
,
"
empty
"
:
"
Bitte ein Feedback eingeben, das abgesendet werden kann.
"
,
"
mailfailure
"
:
"
Die Mail mit dem Feedback konnte nicht versendet werden. Das Feedback wurde lokal abgespeichert.
"
}
feedback_text_en
=
{
"
your-feedback
"
:
"
Your Feedback ...
"
,
"
send
"
:
"
Submit
"
,
"
confirm_send
"
:
"
Confirm submission.
"
,
"
sent
"
:
"
Feedback was submitted. Thank You!
"
,
"
required
"
:
"
Required field
"
,
"
empty
"
:
"
Please fill required fields before submitting.
"
,
"
mailfailure
"
:
"
The mail containing your feedback could not be sent. Your feedback was saved locally.
"
}
def
__init__
(
self
,
feedback_name
,
questions
,
realm
=
None
,
feedback_path
=
'
feedback.json
'
,
lang
=
'
en
'
,
mail_to
=
None
,
mail_from
=
'
feedback@jupyter.rwth-aachen.de
'
,
mail_subject
=
None
,
mail_smtp_host
=
'
smarthost.rwth-aachen.de
'
):
def
__init__
(
self
,
feedback_name
,
questions
,
lang
):
self
.
feedback_name
=
feedback_name
self
.
questions
=
questions
self
.
realm
=
realm
self
.
feedback_path
=
'
.
'
+
feedback_path
if
not
platform
.
system
()
==
'
Windows
'
and
\
not
feedback_path
.
startswith
(
'
.
'
)
else
feedback_path
self
.
lang
=
lang
self
.
mail_to
=
mail_to
se
lf
.
mail_from
=
mail_from
self
.
mail_subject
=
mail_subject
self
.
mail_smtp_host
=
mail_smtp_host
u
se
r_name
=
os
.
environ
.
get
(
'
JUPYTERHUB_USER
'
,
os
.
environ
.
get
(
'
LOGNAME
'
,
os
.
environ
.
get
(
'
USER
'
,
os
.
environ
.
get
(
'
USERNAME
'
,
'
TMP
'
))))
self
.
hashed_username
=
hashlib
.
sha256
(
str
.
encode
(
user_name
)).
hexdigest
()
# Select language
self
.
feedback_scale_options
=
g
etattr
(
self
,
'
feedback_scale_options_
'
+
self
.
lang
)
self
.
feedback_text
=
g
etattr
(
self
,
'
feedback_text_
'
+
self
.
lang
)
self
.
feedback_scale_options
=
g
lobals
()[
'
feedback_scale_options_
'
+
self
.
lang
]
self
.
feedback_text
=
g
lobals
()[
'
feedback_text_
'
+
self
.
lang
]
# Default arguments for toggle_button and textarea
self
.
toggle_args
=
{
"
options
"
:
self
.
feedback_scale_options
,
...
...
@@ -110,17 +100,6 @@ class RWTHFeedback:
# list containing all widgets that require non empty entries
self
.
widgets_required_entries
=
[]
# submission configurations
profile
=
os
.
environ
.
get
(
'
JUPYTERHUB_PROFILE
'
)
if
profile
is
not
None
:
self
.
submission_type
=
'
jupyter
'
self
.
realm
=
f
'
feedback_
{
profile
}
'
if
self
.
realm
is
None
else
self
.
realm
self
.
sub
=
Submission
(
self
.
realm
)
else
:
self
.
submission_type
=
'
json
'
self
.
entry
=
{}
self
.
entries
=
[]
...
...
@@ -173,50 +152,6 @@ class RWTHFeedback:
self
.
update_ui_state
()
def
load_entries
(
self
):
"""
Load entries
Entries are either loaded from juypter service or from json file
according to self.submission_type
"""
if
self
.
submission_type
==
'
jupyter
'
:
# load from jupyter hub submission service
self
.
entries
=
[
submission
[
'
data
'
]
for
submission
in
self
.
sub
.
get
()
if
type
(
submission
[
'
data
'
])
is
dict
]
else
:
# load from json file, create if non existent
if
not
os
.
path
.
isfile
(
self
.
feedback_path
):
# file does not exist, create
with
open
(
self
.
feedback_path
,
mode
=
'
w
'
,
encoding
=
'
utf-8
'
)
as
f
:
json
.
dump
([],
f
)
# hide file
if
platform
.
system
()
==
'
Windows
'
:
subprocess
.
check_call
([
'
attrib
'
,
'
+H
'
,
self
.
feedback_path
])
# load json file into self.entries
with
open
(
self
.
feedback_path
,
mode
=
'
r
'
,
encoding
=
'
utf-8
'
)
as
f
:
self
.
entries
=
json
.
load
(
f
)
def
save_entries
(
self
):
"""
Save entries into json file.
Not used if user is in jupyter cluster.
"""
if
self
.
submission_type
==
'
json
'
:
if
platform
.
system
()
==
'
Windows
'
:
subprocess
.
check_call
([
'
attrib
'
,
'
-H
'
,
self
.
feedback_path
])
# write
with
open
(
self
.
feedback_path
,
mode
=
'
w
'
,
encoding
=
'
utf-8
'
)
as
f
:
json
.
dump
(
self
.
entries
,
f
)
# hide again
if
platform
.
system
()
==
'
Windows
'
:
subprocess
.
check_call
([
'
attrib
'
,
'
+H
'
,
self
.
feedback_path
])
def
on_btn_submit_clicked
(
self
,
_
):
"""
Submit button onClick method
...
...
@@ -229,11 +164,7 @@ class RWTHFeedback:
# set up json entries
self
.
entry
[
'
name
'
]
=
self
.
feedback_name
self
.
entry
[
'
date
'
]
=
"
{}
"
.
format
(
datetime
.
datetime
.
now
())
if
self
.
submission_type
==
'
jupyter
'
:
user_name
=
os
.
environ
.
get
(
'
JUPYTERHUB_USER
'
)
else
:
user_name
=
os
.
environ
.
get
(
'
LOGNAME
'
,
os
.
environ
.
get
(
'
USER
'
,
os
.
environ
.
get
(
'
USERNAME
'
,
'
TMP
'
)))
self
.
entry
[
'
userhash
'
]
=
hashlib
.
sha256
(
str
.
encode
(
user_name
)).
hexdigest
()
self
.
entry
[
'
userhash
'
]
=
self
.
hashed_username
self
.
entry
[
'
answer
'
]
=
{
key
:
w
.
value
for
key
,
w
in
self
.
widgets_container
.
items
()}
self
.
entry
[
'
status
'
]
=
'
saved_locally
'
if
self
.
submission_type
==
'
json
'
else
'
submitted
'
...
...
@@ -258,97 +189,11 @@ class RWTHFeedback:
# update ui
self
.
update_ui_state
()
def
send_mail
(
self
):
"""
Sends JSON file as attachment of a mail to predefined recipient
Sets self.is_submitted to True if mail was sent successfully. False otherwise.
"""
try
:
import
smtplib
from
email.message
import
EmailMessage
msg
=
EmailMessage
()
msg
[
"
From
"
]
=
self
.
mail_from
msg
[
"
Subject
"
]
=
self
.
mail_subject
if
self
.
mail_subject
is
not
None
else
self
.
feedback_name
msg
[
"
To
"
]
=
self
.
mail_to
with
open
(
self
.
feedback_path
,
'
r
'
)
as
f
:
msg
.
add_attachment
(
f
.
read
(),
filename
=
self
.
feedback_path
)
s
=
smtplib
.
SMTP
(
self
.
mail_smtp_host
)
s
.
send_message
(
msg
)
self
.
is_submitted
=
True
except
ConnectionRefusedError
:
# Not connected to the RWTH network
self
.
output
.
clear_output
()
with
self
.
output
:
print
(
self
.
feedback_text
[
'
mailfailure
'
])
self
.
is_submitted
=
False
def
submit
(
self
):
"""
Submit feedback
Sends json file via mail if user is not in jupyter cluster
else the feedback is submitted to jupyters submission service
"""
if
self
.
submission_type
==
'
json
'
:
# dump entries into json file
# append only if not entry does not already exist in json file
self
.
load_entries
()
if
self
.
check_submission_status
()
==
'
idle
'
:
self
.
entries
.
append
(
self
.
entry
)
self
.
save_entries
()
# try to send json file as attachment of mail
if
self
.
mail_to
is
not
None
:
self
.
send_mail
()
# open and set statuses to submitted if mail is successfully sent
if
self
.
is_submitted
:
self
.
load_entries
()
for
entry
in
self
.
entries
:
entry
[
'
status
'
]
=
'
submitted
'
self
.
save_entries
()
else
:
# submit to jupyter submission service
self
.
sub
.
submit
(
self
.
entry
)
self
.
is_submitted
=
True
def
check_submission_status
(
self
):
"""
Check entry submission status
Returns
-------
status: {
'
idle
'
,
'
saved_locally
'
,
'
submitted
'
}, str
submission status
'
idle
'
, if feedback does not exist in self.entires
'
saved_locally
'
, if feedback exists but was not sent
'
submitted
'
, if feedback was already submitted
"""
if
self
.
submission_type
==
'
json
'
:
try
:
for
entry
in
self
.
entries
:
if
self
.
feedback_name
==
entry
[
'
name
'
]:
return
entry
[
'
status
'
]
return
'
idle
'
except
FileNotFoundError
:
return
'
idle
'
else
:
for
entry
in
self
.
entries
:
if
self
.
feedback_name
==
entry
[
'
name
'
]:
return
'
submitted
'
return
'
idle
'
def
update_ui_state
(
self
):
"""
...
...
@@ -412,3 +257,167 @@ class RWTHFeedback:
# disable button and change description
self
.
btn_submit
.
disabled
=
True
self
.
btn_submit
.
description
=
self
.
feedback_text
[
'
sent
'
]
class
RWTHFeedbackJupyter
(
RWTHFeedbackBase
):
def
__init__
(
self
,
feedback_name
,
questions
,
lang
=
'
en
'
,
realm
=
'
feedback
'
):
self
.
realm
=
realm
profile
=
os
.
environ
.
get
(
'
JUPYTERHUB_PROFILE
'
)
self
.
realm
=
f
'
feedback_
{
profile
}
'
if
self
.
realm
is
None
else
self
.
realm
self
.
sub
=
Submission
(
self
.
realm
)
super
().
__init__
(
feedback_name
,
questions
,
lang
)
self
.
submission_type
=
'
jupyter
'
def
load_entries
(
self
):
self
.
entries
=
[
submission
[
'
data
'
]
for
submission
in
self
.
sub
.
get
()
if
type
(
submission
[
'
data
'
])
is
dict
]
def
submit
(
self
):
# submit to jupyter submission service
self
.
sub
.
submit
(
self
.
entry
)
self
.
is_submitted
=
True
class
RWTHFeedbackMail
(
RWTHFeedbackBase
):
def
__init__
(
self
,
feedback_name
,
questions
,
lang
=
'
en
'
,
feedback_path
=
'
feedback.json
'
,
mail_to
=
None
,
mail_from
=
'
feedback@jupyter.rwth-aachen.de
'
,
mail_subject
=
None
,
mail_smtp_host
=
'
smarthost.rwth-aachen.de
'
):
self
.
feedback_path
=
'
.
'
+
feedback_path
if
not
platform
.
system
()
==
'
Windows
'
and
\
not
feedback_path
.
startswith
(
'
.
'
)
else
feedback_path
self
.
mail_to
=
mail_to
self
.
mail_from
=
mail_from
self
.
mail_subject
=
mail_subject
self
.
mail_smtp_host
=
mail_smtp_host
super
().
__init__
(
feedback_name
,
questions
,
lang
)
self
.
submission_type
=
'
json
'
def
save_entries
(
self
):
"""
Save entries into json file.
Not used if user is in jupyter cluster.
"""
if
self
.
submission_type
==
'
json
'
:
if
platform
.
system
()
==
'
Windows
'
:
subprocess
.
check_call
([
'
attrib
'
,
'
-H
'
,
self
.
feedback_path
])
# write
with
open
(
self
.
feedback_path
,
mode
=
'
w
'
,
encoding
=
'
utf-8
'
)
as
f
:
json
.
dump
(
self
.
entries
,
f
)
# hide again
if
platform
.
system
()
==
'
Windows
'
:
subprocess
.
check_call
([
'
attrib
'
,
'
+H
'
,
self
.
feedback_path
])
def
load_entries
(
self
):
if
not
os
.
path
.
isfile
(
self
.
feedback_path
):
# file does not exist, create
with
open
(
self
.
feedback_path
,
mode
=
'
w
'
,
encoding
=
'
utf-8
'
)
as
f
:
json
.
dump
([],
f
)
# hide file
if
platform
.
system
()
==
'
Windows
'
:
subprocess
.
check_call
([
'
attrib
'
,
'
+H
'
,
self
.
feedback_path
])
# load json file into self.entries
with
open
(
self
.
feedback_path
,
mode
=
'
r
'
,
encoding
=
'
utf-8
'
)
as
f
:
self
.
entries
=
json
.
load
(
f
)
def
send_mail
(
self
):
"""
Sends JSON file as attachment of a mail to predefined recipient
Sets self.is_submitted to True if mail was sent successfully. False otherwise.
"""
try
:
import
smtplib
from
email.message
import
EmailMessage
msg
=
EmailMessage
()
msg
[
"
From
"
]
=
self
.
mail_from
msg
[
"
Subject
"
]
=
self
.
mail_subject
if
self
.
mail_subject
is
not
None
else
self
.
feedback_name
msg
[
"
To
"
]
=
self
.
mail_to
with
open
(
self
.
feedback_path
,
'
r
'
)
as
f
:
msg
.
add_attachment
(
f
.
read
(),
filename
=
self
.
feedback_path
)
s
=
smtplib
.
SMTP
(
self
.
mail_smtp_host
)
s
.
send_message
(
msg
)
self
.
is_submitted
=
True
except
ConnectionRefusedError
:
# Not connected to the RWTH network
self
.
output
.
clear_output
()
with
self
.
output
:
print
(
self
.
feedback_text
[
'
mailfailure
'
])
self
.
is_submitted
=
False
def
submit
(
self
):
# dump entries into json file
# append only if not entry does not already exist in json file
self
.
load_entries
()
if
self
.
check_submission_status
()
==
'
idle
'
:
self
.
entries
.
append
(
self
.
entry
)
self
.
save_entries
()
# try to send json file as attachment of mail
if
self
.
mail_to
is
not
None
:
self
.
send_mail
()
# open and set statuses to submitted if mail is successfully sent
if
self
.
is_submitted
:
self
.
load_entries
()
for
entry
in
self
.
entries
:
entry
[
'
status
'
]
=
'
submitted
'
self
.
save_entries
()
class
RWTHFeedback
:
"""
RWTHFeedback calling specific classes dependent on use cases
Parameters
----------
feedback_name: str
the feedbacks name
questions: dict
feedback options to be filled out
lang: str, optional
feedback language, scales are shown in that language
-- Only for RWTHJupyter usage ---
realm: str, optional
jupyter submission realm in which the feedback should be stored, is set automatically if None
-- Only for Offline usage --
feedback_path: str, optional
path in which a feedback json file should be stored
mail_to: str, optional
mail adress to which the feedback should be sent when submitted
mail_from: str, optional
mail adress from which the feedback should be sent when submitted
mail_subject: str, optional
subject of the mail
mail_smtp_host: str, optional
smtp host
"""
def
__init__
(
self
,
feedback_name
,
questions
,
lang
=
'
de
'
,
realm
=
None
,
feedback_path
=
'
feedback.json
'
,
mail_to
=
None
,
mail_from
=
'
feedback@jupyter.rwth-aachen.de
'
,
mail_subject
=
None
,
mail_smtp_host
=
'
smarthost.rwth-aachen.de
'
):
profile
=
os
.
environ
.
get
(
'
JUPYTERHUB_PROFILE
'
)
if
profile
is
not
None
:
RWTHFeedbackJupyter
(
feedback_name
,
questions
,
lang
,
realm
)
else
:
RWTHFeedbackMail
(
feedback_name
,
questions
,
lang
,
feedback_path
,
mail_to
,
mail_from
,
mail_subject
,
mail_smtp_host
)
\ No newline at end of file
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
register
or
sign in
to comment