6
6
# The full license is in the file LICENSE, distributed with this software.
7
7
# -----------------------------------------------------------------------------
8
8
9
+ import re
10
+
9
11
from tornado .web import authenticated , HTTPError
10
12
from wtforms import Form , StringField , BooleanField , validators
13
+ from wtforms .validators import ValidationError
11
14
12
15
from qiita_pet .handlers .base_handlers import BaseHandler
13
16
from qiita_pet .handlers .api_proxy import user_jobs_get_req
21
24
22
25
23
26
class UserProfile (Form ):
27
+ def validate_general (value : str , infomsg : str , url_prefix : str ):
28
+ """Validate basic user inputs, i.e. check for leading/trailing
29
+ whitespaces and leading URL prefix, like http://scholar.google.com/
30
+
31
+ Parameters
32
+ ----------
33
+ value : str
34
+ The WTform user input string.
35
+ infomsg : str
36
+ An error message to inform the user how to extract the correct
37
+ value.
38
+ url_prefix : str
39
+ The URL prefix of the social network
40
+
41
+ Returns
42
+ -------
43
+ None in case of empty input, otherwise the input value
44
+
45
+ Raises
46
+ ------
47
+ ValidationError if
48
+ a) input has leading or trailing whitespaces
49
+ b) input starts with the given url_prefix
50
+ """
51
+ if (value is None ) or (value == "" ):
52
+ # nothing to complain, as input is empty
53
+ return None
54
+
55
+ if value != value .strip ():
56
+ raise ValidationError (
57
+ 'Please remove all leading and trailing whitespaces from your '
58
+ 'input.<br/>%s' % infomsg )
59
+
60
+ if len (url_prefix ) > 0 :
61
+ isPrefix = re .search ("^%s" % url_prefix , value )
62
+ if isPrefix is not None :
63
+ raise ValidationError (
64
+ 'Please remove the "%s" part from your input.<br/>%s' % (
65
+ isPrefix [0 ], infomsg ))
66
+
67
+ # if there is still no error raised, we return the actual value of the
68
+ # user input
69
+ return value
70
+
71
+ def validator_orcid_id (form : Form , field : StringField ):
72
+ """A WTForm validator to check if user input follows ORCID syntax.
73
+
74
+ Parameters
75
+ ----------
76
+ form : wtforms.Form
77
+ The WTform form enclosing the user input field.
78
+ field : wtforms.StringField
79
+ The WTform user input field.
80
+
81
+ Returns
82
+ -------
83
+ True, if user input is OK.
84
+
85
+ Raises
86
+ ------
87
+ ValidationError if user input is not valid
88
+ """
89
+ infomsg = ('Enter only your 16 digit numerical ORCID identifier, where'
90
+ ' every four digits are separated with a dash "-". An '
91
+ 'example is: 0000-0002-0975-9019' )
92
+ value = UserProfile .validate_general (
93
+ field .data , infomsg , 'https://orcid.org' )
94
+ if value is None :
95
+ return True
96
+
97
+ if re .search (r"^\d{4}-\d{4}-\d{4}-\d{4}$" , value ) is None :
98
+ raise ValidationError (
99
+ "Your input does not follow the required format.<br/>%s" %
100
+ infomsg )
101
+
102
+ def validator_gscholar_id (form , field ):
103
+ """A WTForm validator to check if user input follows google scholar ID
104
+ syntax.
105
+
106
+ Parameters
107
+ ----------
108
+ form : wtforms.Form
109
+ The WTform form enclosing the user input field.
110
+ field : wtforms.StringField
111
+ The WTform user input field.
112
+
113
+ Returns
114
+ -------
115
+ True, if user input is OK.
116
+
117
+ Raises
118
+ ------
119
+ ValidationError if user input is not valid
120
+ """
121
+ infomsg = ('To retrieve your google scholar ID, surf to your profile '
122
+ 'and copy the URL in your browser. It might read like '
123
+ 'https://scholar.google.com/citations?user=_e3QL94AAAAJ&'
124
+ 'hl=en<br/>Ignore everything left of the "?". The right '
125
+ 'part is a set of key=value pairs, separated by "&" '
126
+ 'characters. Find the key "user=", the right part up to '
127
+ 'the next "&" is your google scholar ID, in the example: '
128
+ '"_e3QL94AAAAJ"' )
129
+ # we need a regex here, since we don't know the TLD the user is
130
+ # presenting to us
131
+ value = UserProfile .validate_general (
132
+ field .data , infomsg , r'https://scholar.google.\w{1,3}/citations\?' )
133
+ if value is None :
134
+ return True
135
+
136
+ if '&' in value :
137
+ raise ValidationError (
138
+ 'Your input contains multiple key=value pairs (we found at '
139
+ 'least one "&" character).<br/>%s' % infomsg )
140
+ if 'user=' in value :
141
+ raise ValidationError (
142
+ 'Please remove the key "user" and the "=" character from '
143
+ 'your input.<br/>%s' % infomsg )
144
+ if value .startswith ('=' ):
145
+ raise ValidationError (
146
+ 'Please remove leading "=" characters from your input.'
147
+ '<br/>%s' % infomsg )
148
+
149
+ def validator_rgate_id (form , field ):
150
+ """A WTForm validator to check if user input follows ResearchGate
151
+ user names.
152
+
153
+ Parameters
154
+ ----------
155
+ form : wtforms.Form
156
+ The WTform form enclosing the user input field.
157
+ field : wtforms.StringField
158
+ The WTform user input field.
159
+
160
+ Returns
161
+ -------
162
+ True, if user input is OK.
163
+
164
+ Raises
165
+ ------
166
+ ValidationError if user input is not valid
167
+ """
168
+ infomsg = ('To retrieve your ResearchGate ID, surf to your profile '
169
+ 'and copy the URL in your browser. It might read like '
170
+ 'https://www.researchgate.net/profile/Rob-Knight<br/>'
171
+ 'Your ID is the part right of the last "/", in the example:'
172
+ ' "Rob-Knight"' )
173
+ value = UserProfile .validate_general (
174
+ field .data , infomsg , 'https://www.researchgate.net/profile/' )
175
+ if value is None :
176
+ return True
177
+
24
178
name = StringField ("Name" , [validators .required ()])
25
179
affiliation = StringField ("Affiliation" )
26
180
address = StringField ("Address" )
27
181
phone = StringField ("Phone" )
28
182
receive_processing_job_emails = BooleanField (
29
183
"Receive Processing Job Emails?" )
30
184
185
+ social_orcid = StringField (
186
+ "ORCID" , [validator_orcid_id ], description = "0000-0002-0975-9019" )
187
+ social_googlescholar = StringField (
188
+ "Google Scholar" , [validator_gscholar_id ], description = "_e3QL94AAAAJ" )
189
+ social_researchgate = StringField (
190
+ "ResearchGate" , [validator_rgate_id ], description = "Rob-Knight" )
191
+
31
192
32
193
class UserProfileHandler (BaseHandler ):
33
194
"""Displays user profile page and handles profile updates"""
@@ -44,11 +205,11 @@ def post(self):
44
205
msg = ""
45
206
user = self .current_user
46
207
action = self .get_argument ("action" )
208
+ form_data = UserProfile ()
47
209
if action == "profile" :
48
- # tuple of colmns available for profile
210
+ # tuple of columns available for profile
49
211
# FORM INPUT NAMES MUST MATCH DB COLUMN NAMES
50
212
not_str_fields = ('receive_processing_job_emails' )
51
- form_data = UserProfile ()
52
213
form_data .process (data = self .request .arguments )
53
214
profile = {name : data [0 ].decode ('ascii' )
54
215
if name not in not_str_fields else
@@ -59,16 +220,19 @@ def post(self):
59
220
for field in form_data :
60
221
if field .name not in not_str_fields :
61
222
field .data = field .data [0 ].decode ('ascii' )
62
- try :
63
- user .info = profile
64
- msg = "Profile updated successfully"
65
- except Exception as e :
66
- msg = "ERROR: profile could not be updated"
67
- LogEntry .create ('Runtime' , "Cound not update profile: %s" %
68
- str (e ), info = {'User' : user .id })
223
+ if form_data .validate () is False :
224
+ msg = ("ERROR: profile could not be updated"
225
+ " as some of your above inputs must be corrected." )
226
+ else :
227
+ try :
228
+ user .info = profile
229
+ msg = "Profile updated successfully"
230
+ except Exception as e :
231
+ msg = "ERROR: profile could not be updated"
232
+ LogEntry .create ('Runtime' , "Cound not update profile: %s" %
233
+ str (e ), info = {'User' : user .id })
69
234
70
235
elif action == "password" :
71
- form_data = UserProfile ()
72
236
form_data .process (data = user .info )
73
237
oldpass = self .get_argument ("oldpass" )
74
238
newpass = self .get_argument ("newpass" )
0 commit comments