1 # GNU MediaGoblin -- federated, autonomous media hosting
2 # Copyright (C) 2011, 2012 MediaGoblin contributors. See AUTHORS.
4 # This program is free software: you can redistribute it and/or modify
5 # it under the terms of the GNU Affero General Public License as published by
6 # the Free Software Foundation, either version 3 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU Affero General Public License for more details.
14 # You should have received a copy of the GNU Affero General Public License
15 # along with this program. If not, see <http://www.gnu.org/licenses/>.
20 from mediagoblin
import mg_globals
21 from mediagoblin
.tools
.crypto
import get_timed_signer_url
22 from mediagoblin
.db
.models
import User
23 from mediagoblin
.tools
.mail
import (normalize_email
, send_email
,
25 from mediagoblin
.tools
.template
import render_template
26 from mediagoblin
.tools
.translate
import lazy_pass_to_ugettext
as _
27 from mediagoblin
.tools
.pluginapi
import hook_handle
28 from mediagoblin
import auth
30 _log
= logging
.getLogger(__name__
)
33 def normalize_user_or_email_field(allow_email
=True, allow_user
=True):
35 Check if we were passed a field that matches a username and/or email
38 This is useful for fields that can take either a username or email
39 address. Use the parameters if you want to only allow a username for
41 message
= _(u
'Invalid User name or email address.')
42 nomail_msg
= _(u
"This field does not take email addresses.")
43 nouser_msg
= _(u
"This field requires an email address.")
45 def _normalize_field(form
, field
):
46 email
= u
'@' in field
.data
47 if email
: # normalize email address casing
49 raise wtforms
.ValidationError(nomail_msg
)
50 wtforms
.validators
.Email()(form
, field
)
51 field
.data
= normalize_email(field
.data
)
52 else: # lower case user names
54 raise wtforms
.ValidationError(nouser_msg
)
55 wtforms
.validators
.Length(min=3, max=30)(form
, field
)
56 wtforms
.validators
.Regexp(r
'^\w+$')(form
, field
)
57 field
.data
= field
.data
.lower()
58 if field
.data
is None: # should not happen, but be cautious anyway
59 raise wtforms
.ValidationError(message
)
60 return _normalize_field
63 EMAIL_VERIFICATION_TEMPLATE
= (
65 u
"token={verification_key}")
68 def send_verification_email(user
, request
, email
=None,
71 Send the verification email to users to activate their accounts.
75 - request: the request
80 if not rendered_email
:
81 verification_key
= get_timed_signer_url('mail_verification_token') \
83 rendered_email
= render_template(
84 request
, 'mediagoblin/auth/verification_email.txt',
85 {'username': user
.username
,
86 'verification_url': EMAIL_VERIFICATION_TEMPLATE
.format(
87 uri
=request
.urlgen('mediagoblin.auth.verify_email',
89 verification_key
=verification_key
)})
91 # TODO: There is no error handling in place
93 mg_globals
.app_config
['email_sender_address'],
96 # Due to the distributed nature of GNU MediaGoblin, we should
97 # find a way to send some additional information about the
98 # specific GNU MediaGoblin instance in the subject line. For
99 # example "GNU MediaGoblin @ Wandborg - [...]".
100 'GNU MediaGoblin - Verify your email!',
104 EMAIL_FP_VERIFICATION_TEMPLATE
= (
106 u
"token={fp_verification_key}")
109 def send_fp_verification_email(user
, request
):
111 Send the verification email to users to change their password.
114 - user: a user object
115 - request: the request
117 fp_verification_key
= get_timed_signer_url('mail_verification_token') \
120 rendered_email
= render_template(
121 request
, 'mediagoblin/auth/fp_verification_email.txt',
122 {'username': user
.username
,
123 'verification_url': EMAIL_FP_VERIFICATION_TEMPLATE
.format(
124 uri
=request
.urlgen('mediagoblin.auth.verify_forgot_password',
126 fp_verification_key
=fp_verification_key
)})
128 # TODO: There is no error handling in place
130 mg_globals
.app_config
['email_sender_address'],
132 'GNU MediaGoblin - Change forgotten password!',
136 def basic_extra_validation(register_form
, *args
):
137 users_with_username
= User
.query
.filter_by(
138 username
=register_form
.username
.data
).count()
139 users_with_email
= User
.query
.filter_by(
140 email
=register_form
.email
.data
).count()
142 extra_validation_passes
= True
144 if users_with_username
:
145 register_form
.username
.errors
.append(
146 _(u
'Sorry, a user with that name already exists.'))
147 extra_validation_passes
= False
149 register_form
.email
.errors
.append(
150 _(u
'Sorry, a user with that email address already exists.'))
151 extra_validation_passes
= False
153 return extra_validation_passes
156 def register_user(request
, register_form
):
157 """ Handle user registration """
158 extra_validation_passes
= auth
.extra_validation(register_form
)
160 if extra_validation_passes
:
162 user
= auth
.create_user(register_form
)
165 request
.session
['user_id'] = unicode(user
.id)
166 request
.session
.save()
168 # send verification email
169 email_debug_message(request
)
170 send_verification_email(user
, request
)
177 def check_login_simple(username
, password
):
178 user
= auth
.get_user(username
=username
)
180 _log
.info("User %r not found", username
)
181 hook_handle("auth_fake_login_attempt")
183 if not auth
.check_password(password
, user
.pw_hash
):
184 _log
.warn("Wrong password for %r", username
)
186 _log
.info("Logging %r in", username
)
190 def check_auth_enabled():
191 if not hook_handle('authentication'):
192 _log
.warning('No authentication is enabled')
198 def no_auth_logout(request
):
199 """Log out the user if authentication_disabled, but don't delete the messages"""
200 if not mg_globals
.app
.auth
and 'user_id' in request
.session
:
201 del request
.session
['user_id']
202 request
.session
.save()
205 def create_basic_user(form
):
207 user
.username
= form
.username
.data
208 user
.email
= form
.email
.data