##// END OF EJS Templates
Implemented password reset(forms/models/ tasks) and mailing tasks....
marcink -
r474:a3d9d24a celery
parent child Browse files
Show More
@@ -0,0 +1,118 b''
1 import logging
2 import smtplib
3 import mimetypes
4 from email.mime.multipart import MIMEMultipart
5 from email.mime.image import MIMEImage
6 from email.mime.audio import MIMEAudio
7 from email.mime.base import MIMEBase
8 from email.mime.text import MIMEText
9 from email.utils import formatdate
10 from email import encoders
11
12 class SmtpMailer(object):
13 """simple smtp mailer class
14
15 mailer = SmtpMailer(mail_from, user, passwd, mail_server, mail_port, ssl, tls)
16 mailer.send(recipients, subject, body, attachment_files)
17
18 :param recipients might be a list of string or single string
19 :param attachment_files is a dict of {filename:location}
20 it tries to guess the mimetype and attach the file
21 """
22
23 def __init__(self, mail_from, user, passwd, mail_server,
24 mail_port=None, ssl=False, tls=False):
25
26 self.mail_from = mail_from
27 self.mail_server = mail_server
28 self.mail_port = mail_port
29 self.user = user
30 self.passwd = passwd
31 self.ssl = ssl
32 self.tls = tls
33 self.debug = False
34
35 def send(self, recipients=[], subject='', body='', attachment_files={}):
36
37 if isinstance(recipients, basestring):
38 recipients = [recipients]
39 if self.ssl:
40 smtp_serv = smtplib.SMTP_SSL(self.mail_server, self.mail_port)
41 else:
42 smtp_serv = smtplib.SMTP(self.mail_server, self.mail_port)
43
44 if self.tls:
45 smtp_serv.starttls()
46
47 if self.debug:
48 smtp_serv.set_debuglevel(1)
49
50 smtp_serv.ehlo("mailer")
51
52 #if server requires authorization you must provide login and password
53 smtp_serv.login(self.user, self.passwd)
54
55 date_ = formatdate(localtime=True)
56 msg = MIMEMultipart()
57 msg['From'] = self.mail_from
58 msg['To'] = ','.join(recipients)
59 msg['Date'] = date_
60 msg['Subject'] = subject
61 msg.preamble = 'You will not see this in a MIME-aware mail reader.\n'
62
63 msg.attach(MIMEText(body))
64
65 if attachment_files:
66 self.__atach_files(msg, attachment_files)
67
68 smtp_serv.sendmail(self.mail_from, recipients, msg.as_string())
69 logging.info('MAIL SEND TO: %s' % recipients)
70 smtp_serv.quit()
71
72
73 def __atach_files(self, msg, attachment_files):
74 if isinstance(attachment_files, dict):
75 for f_name, msg_file in attachment_files.items():
76 ctype, encoding = mimetypes.guess_type(f_name)
77 logging.info("guessing file %s type based on %s" , ctype, f_name)
78 if ctype is None or encoding is not None:
79 # No guess could be made, or the file is encoded (compressed), so
80 # use a generic bag-of-bits type.
81 ctype = 'application/octet-stream'
82 maintype, subtype = ctype.split('/', 1)
83 if maintype == 'text':
84 # Note: we should handle calculating the charset
85 file_part = MIMEText(self.get_content(msg_file),
86 _subtype=subtype)
87 elif maintype == 'image':
88 file_part = MIMEImage(self.get_content(msg_file),
89 _subtype=subtype)
90 elif maintype == 'audio':
91 file_part = MIMEAudio(self.get_content(msg_file),
92 _subtype=subtype)
93 else:
94 file_part = MIMEBase(maintype, subtype)
95 file_part.set_payload(self.get_content(msg_file))
96 # Encode the payload using Base64
97 encoders.encode_base64(msg)
98 # Set the filename parameter
99 file_part.add_header('Content-Disposition', 'attachment',
100 filename=f_name)
101 file_part.add_header('Content-Type', ctype, name=f_name)
102 msg.attach(file_part)
103 else:
104 raise Exception('Attachment files should be'
105 'a dict in format {"filename":"filepath"}')
106
107 def get_content(self, msg_file):
108 '''
109 Get content based on type, if content is a string do open first
110 else just read because it's a probably open file object
111 @param msg_file:
112 '''
113 if isinstance(msg_file, str):
114 return open(msg_file, "rb").read()
115 else:
116 #just for safe seek to 0
117 msg_file.seek(0)
118 return msg_file.read()
@@ -0,0 +1,54 b''
1 ## -*- coding: utf-8 -*-
2 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
3 <html xmlns="http://www.w3.org/1999/xhtml" id="mainhtml">
4 <head>
5 <title>${_('Reset You password to hg-app')}</title>
6 <meta http-equiv="Content-Type" content="text/html;charset=utf-8" />
7 <link rel="icon" href="/images/hgicon.png" type="image/png" />
8 <meta name="robots" content="index, nofollow"/>
9
10 <!-- stylesheets -->
11 <link rel="stylesheet" type="text/css" href="/css/reset.css" />
12 <link rel="stylesheet" type="text/css" href="/css/style.css" media="screen" />
13 <link id="color" rel="stylesheet" type="text/css" href="/css/colors/blue.css" />
14
15 <!-- scripts -->
16
17 </head>
18 <body>
19 <div id="register">
20
21 <div class="title">
22 <h5>${_('Reset You password to hg-app')}</h5>
23 <div class="corner tl"></div>
24 <div class="corner tr"></div>
25 </div>
26 <div class="inner">
27 ${h.form(url('password_reset'))}
28 <div class="form">
29 <!-- fields -->
30 <div class="fields">
31
32 <div class="field">
33 <div class="label">
34 <label for="email">${_('Email address')}:</label>
35 </div>
36 <div class="input">
37 ${h.text('email')}
38 </div>
39 </div>
40
41 <div class="buttons">
42 <div class="nohighlight">
43 ${h.submit('send','Reset my password',class_="ui-button ui-widget ui-state-default ui-corner-all")}
44 <div class="activation_msg">${_('Your new password will be send to matching email address')}</div>
45 </div>
46 </div>
47 </div>
48 </div>
49 ${h.end_form()}
50 </div>
51 </div>
52 </body>
53 </html>
54
@@ -8,6 +8,7 b' CELERY_IMPORTS = ("pylons_app.lib.celery'
8 CELERY_RESULT_BACKEND = "database"
8 CELERY_RESULT_BACKEND = "database"
9 CELERY_RESULT_DBURI = "sqlite:///hg_app.db"
9 CELERY_RESULT_DBURI = "sqlite:///hg_app.db"
10
10
11 BROKER_CONNECTION_MAX_RETRIES = 30
11
12
12 ## Broker settings.
13 ## Broker settings.
13 BROKER_HOST = "localhost"
14 BROKER_HOST = "localhost"
@@ -1,32 +1,37 b''
1 ################################################################################
1 ################################################################################
2 ################################################################################
2 ################################################################################
3 # pylons_app - Pylons environment configuration #
3 # hg-app - Pylons environment configuration #
4 # #
4 # #
5 # The %(here)s variable will be replaced with the parent directory of this file#
5 # The %(here)s variable will be replaced with the parent directory of this file#
6 ################################################################################
6 ################################################################################
7
7
8 [DEFAULT]
8 [DEFAULT]
9 debug = true
9 debug = true
10 ############################################
10 ################################################################################
11 ## Uncomment and replace with the address ##
11 ## Uncomment and replace with the address which should receive ##
12 ## which should receive any error reports ##
12 ## any error reports after application crash ##
13 ############################################
13 ## Additionally those settings will be used by hg-app mailing system ##
14 ################################################################################
14 #email_to = admin@localhost
15 #email_to = admin@localhost
16 #error_email_from = paste_error@localhost
17 #app_email_from = hg-app-noreply@localhost
18 #error_message =
19
15 #smtp_server = mail.server.com
20 #smtp_server = mail.server.com
16 #error_email_from = paste_error@localhost
17 #smtp_username =
21 #smtp_username =
18 #smtp_password =
22 #smtp_password =
19 #error_message = 'mercurial crash !'
23 #smtp_port =
24 #smtp_use_tls =
20
25
21 [server:main]
26 [server:main]
22 ##nr of threads to spawn
27 ##nr of threads to spawn
23 threadpool_workers = 5
28 threadpool_workers = 5
24
29
25 ##max request before
30 ##max request before
26 threadpool_max_requests = 2
31 threadpool_max_requests = 6
27
32
28 ##option to use threads of process
33 ##option to use threads of process
29 use_threadpool = true
34 use_threadpool = false
30
35
31 use = egg:Paste#http
36 use = egg:Paste#http
32 host = 127.0.0.1
37 host = 127.0.0.1
@@ -110,10 +110,11 b' def make_map(config):'
110 #SEARCH
110 #SEARCH
111 map.connect('search', '/_admin/search', controller='search')
111 map.connect('search', '/_admin/search', controller='search')
112
112
113 #LOGIN/LOGOUT
113 #LOGIN/LOGOUT/REGISTER/SIGN IN
114 map.connect('login_home', '/_admin/login', controller='login')
114 map.connect('login_home', '/_admin/login', controller='login')
115 map.connect('logout_home', '/_admin/logout', controller='login', action='logout')
115 map.connect('logout_home', '/_admin/logout', controller='login', action='logout')
116 map.connect('register', '/_admin/register', controller='login', action='register')
116 map.connect('register', '/_admin/register', controller='login', action='register')
117 map.connect('reset_password', '/_admin/password_reset', controller='login', action='password_reset')
117
118
118 #FEEDS
119 #FEEDS
119 map.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
120 map.connect('rss_feed_home', '/{repo_name:.*}/feed/rss',
@@ -28,7 +28,9 b' from pylons import request, response, se'
28 from pylons.controllers.util import abort, redirect
28 from pylons.controllers.util import abort, redirect
29 from pylons_app.lib.auth import AuthUser, HasPermissionAnyDecorator
29 from pylons_app.lib.auth import AuthUser, HasPermissionAnyDecorator
30 from pylons_app.lib.base import BaseController, render
30 from pylons_app.lib.base import BaseController, render
31 from pylons_app.model.forms import LoginForm, RegisterForm
31 import pylons_app.lib.helpers as h
32 from pylons.i18n.translation import _
33 from pylons_app.model.forms import LoginForm, RegisterForm, PasswordResetForm
32 from pylons_app.model.user_model import UserModel
34 from pylons_app.model.user_model import UserModel
33 import formencode
35 import formencode
34 import logging
36 import logging
@@ -42,7 +44,7 b' class LoginController(BaseController):'
42
44
43 def index(self):
45 def index(self):
44 #redirect if already logged in
46 #redirect if already logged in
45 c.came_from = request.GET.get('came_from',None)
47 c.came_from = request.GET.get('came_from', None)
46
48
47 if c.hg_app_user.is_authenticated:
49 if c.hg_app_user.is_authenticated:
48 return redirect(url('hg_home'))
50 return redirect(url('hg_home'))
@@ -82,7 +84,7 b' class LoginController(BaseController):'
82
84
83 return render('/login.html')
85 return render('/login.html')
84
86
85 @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate',
87 @HasPermissionAnyDecorator('hg.admin', 'hg.register.auto_activate',
86 'hg.register.manual_activate')
88 'hg.register.manual_activate')
87 def register(self):
89 def register(self):
88 user_model = UserModel()
90 user_model = UserModel()
@@ -99,6 +101,8 b' class LoginController(BaseController):'
99 form_result = register_form.to_python(dict(request.POST))
101 form_result = register_form.to_python(dict(request.POST))
100 form_result['active'] = c.auto_active
102 form_result['active'] = c.auto_active
101 user_model.create_registration(form_result)
103 user_model.create_registration(form_result)
104 h.flash(_('You have successfully registered into hg-app'),
105 category='success')
102 return redirect(url('login_home'))
106 return redirect(url('login_home'))
103
107
104 except formencode.Invalid as errors:
108 except formencode.Invalid as errors:
@@ -110,7 +114,29 b' class LoginController(BaseController):'
110 encoding="UTF-8")
114 encoding="UTF-8")
111
115
112 return render('/register.html')
116 return render('/register.html')
113
117
118 def password_reset(self):
119 user_model = UserModel()
120 if request.POST:
121
122 password_reset_form = PasswordResetForm()()
123 try:
124 form_result = password_reset_form.to_python(dict(request.POST))
125 user_model.reset_password(form_result)
126 h.flash(_('Your new password was sent'),
127 category='success')
128 return redirect(url('login_home'))
129
130 except formencode.Invalid as errors:
131 return htmlfill.render(
132 render('/password_reset.html'),
133 defaults=errors.value,
134 errors=errors.error_dict or {},
135 prefix_error=False,
136 encoding="UTF-8")
137
138 return render('/password_reset.html')
139
114 def logout(self):
140 def logout(self):
115 session['hg_app_user'] = AuthUser()
141 session['hg_app_user'] = AuthUser()
116 session.save()
142 session.save()
@@ -34,9 +34,36 b' from sqlalchemy.orm.exc import NoResultF'
34 import bcrypt
34 import bcrypt
35 from decorator import decorator
35 from decorator import decorator
36 import logging
36 import logging
37 import random
37
38
38 log = logging.getLogger(__name__)
39 log = logging.getLogger(__name__)
39
40
41 class PasswordGenerator(object):
42 """This is a simple class for generating password from
43 different sets of characters
44 usage:
45 passwd_gen = PasswordGenerator()
46 #print 8-letter password containing only big and small letters of alphabet
47 print passwd_gen.gen_password(8, passwd_gen.ALPHABETS_BIG_SMALL)
48 """
49 ALPHABETS_NUM = r'''1234567890'''#[0]
50 ALPHABETS_SMALL = r'''qwertyuiopasdfghjklzxcvbnm'''#[1]
51 ALPHABETS_BIG = r'''QWERTYUIOPASDFGHJKLZXCVBNM'''#[2]
52 ALPHABETS_SPECIAL = r'''`-=[]\;',./~!@#$%^&*()_+{}|:"<>?''' #[3]
53 ALPHABETS_FULL = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM + ALPHABETS_SPECIAL#[4]
54 ALPHABETS_ALPHANUM = ALPHABETS_BIG + ALPHABETS_SMALL + ALPHABETS_NUM#[5]
55 ALPHABETS_BIG_SMALL = ALPHABETS_BIG + ALPHABETS_SMALL
56 ALPHABETS_ALPHANUM_BIG = ALPHABETS_BIG + ALPHABETS_NUM#[6]
57 ALPHABETS_ALPHANUM_SMALL = ALPHABETS_SMALL + ALPHABETS_NUM#[7]
58
59 def __init__(self, passwd=''):
60 self.passwd = passwd
61
62 def gen_password(self, len, type):
63 self.passwd = ''.join([random.choice(type) for _ in xrange(len)])
64 return self.passwd
65
66
40 def get_crypt_password(password):
67 def get_crypt_password(password):
41 """Cryptographic function used for password hashing based on sha1
68 """Cryptographic function used for password hashing based on sha1
42 @param password: password to hash
69 @param password: password to hash
@@ -231,9 +258,9 b' class LoginRequired(object):'
231
258
232 p = request.environ.get('PATH_INFO')
259 p = request.environ.get('PATH_INFO')
233 if request.environ.get('QUERY_STRING'):
260 if request.environ.get('QUERY_STRING'):
234 p+='?'+request.environ.get('QUERY_STRING')
261 p += '?' + request.environ.get('QUERY_STRING')
235 log.debug('redirecting to login page with %s',p)
262 log.debug('redirecting to login page with %s', p)
236 return redirect(url('login_home',came_from=p))
263 return redirect(url('login_home', came_from=p))
237
264
238 class PermsDecorator(object):
265 class PermsDecorator(object):
239 """Base class for decorators"""
266 """Base class for decorators"""
@@ -1,5 +1,8 b''
1 from vcs.utils.lazy import LazyProperty
1 from vcs.utils.lazy import LazyProperty
2 import logging
2 import logging
3 import os
4 import sys
5 import traceback
3
6
4 log = logging.getLogger(__name__)
7 log = logging.getLogger(__name__)
5
8
@@ -11,14 +14,13 b' class ResultWrapper(object):'
11 def result(self):
14 def result(self):
12 return self.task
15 return self.task
13
16
14 def run_task(task,async,*args,**kwargs):
17 def run_task(task,*args,**kwargs):
15 try:
18 try:
16 t = task.delay(*args,**kwargs)
19 t = task.delay(*args,**kwargs)
17 log.info('running task %s',t.task_id)
20 log.info('running task %s',t.task_id)
18 if not async:
19 t.wait()
20 return t
21 return t
21 except:
22 except:
23 log.error(traceback.format_exc())
22 #pure sync version
24 #pure sync version
23 return ResultWrapper(task(*args,**kwargs))
25 return ResultWrapper(task(*args,**kwargs))
24 No newline at end of file
26
@@ -1,18 +1,82 b''
1 from celery.decorators import task
1 from celery.decorators import task
2 from celery.task.sets import subtask
2 from datetime import datetime, timedelta
3 from datetime import datetime, timedelta
4 from os.path import dirname as dn
5 from pylons.i18n.translation import _
6 from pylons_app.lib.celerylib import run_task
3 from pylons_app.lib.helpers import person
7 from pylons_app.lib.helpers import person
8 from pylons_app.lib.smtp_mailer import SmtpMailer
4 from pylons_app.lib.utils import OrderedDict
9 from pylons_app.lib.utils import OrderedDict
5 from time import mktime
10 from time import mktime
11 from vcs.backends.hg import MercurialRepository
12 import ConfigParser
6 import calendar
13 import calendar
7 import logging
14 import os
8 from vcs.backends.hg import MercurialRepository
15 import traceback
16
17
18 root = dn(dn(dn(dn(os.path.realpath(__file__)))))
19 config = ConfigParser.ConfigParser({'here':root})
20 config.read('%s/development.ini' % root)
21
22 __all__ = ['whoosh_index', 'get_commits_stats',
23 'reset_user_password', 'send_email']
24
25 def get_session():
26 from sqlalchemy import engine_from_config
27 from sqlalchemy.orm import sessionmaker, scoped_session
28 engine = engine_from_config(dict(config.items('app:main')), 'sqlalchemy.db1.')
29 sa = scoped_session(sessionmaker(bind=engine))
30 return sa
9
31
10 log = logging.getLogger(__name__)
32 def get_hg_settings():
33 from pylons_app.model.db import HgAppSettings
34 try:
35 sa = get_session()
36 ret = sa.query(HgAppSettings).all()
37 finally:
38 sa.remove()
39
40 if not ret:
41 raise Exception('Could not get application settings !')
42 settings = {}
43 for each in ret:
44 settings['hg_app_' + each.app_settings_name] = each.app_settings_value
45
46 return settings
11
47
12 @task()
48 def get_hg_ui_settings():
13 def whoosh_index(repo_location,full_index):
49 from pylons_app.model.db import HgAppUi
50 try:
51 sa = get_session()
52 ret = sa.query(HgAppUi).all()
53 finally:
54 sa.remove()
55
56 if not ret:
57 raise Exception('Could not get application ui settings !')
58 settings = {}
59 for each in ret:
60 k = each.ui_key
61 v = each.ui_value
62 if k == '/':
63 k = 'root_path'
64
65 if k.find('.') != -1:
66 k = k.replace('.', '_')
67
68 if each.ui_section == 'hooks':
69 v = each.ui_active
70
71 settings[each.ui_section + '_' + k] = v
72
73 return settings
74
75 @task
76 def whoosh_index(repo_location, full_index):
77 log = whoosh_index.get_logger()
14 from pylons_app.lib.indexers import DaemonLock
78 from pylons_app.lib.indexers import DaemonLock
15 from pylons_app.lib.indexers.daemon import WhooshIndexingDaemon,LockHeld
79 from pylons_app.lib.indexers.daemon import WhooshIndexingDaemon, LockHeld
16 try:
80 try:
17 l = DaemonLock()
81 l = DaemonLock()
18 WhooshIndexingDaemon(repo_location=repo_location)\
82 WhooshIndexingDaemon(repo_location=repo_location)\
@@ -23,10 +87,12 b' def whoosh_index(repo_location,full_inde'
23 log.info('LockHeld')
87 log.info('LockHeld')
24 return 'LockHeld'
88 return 'LockHeld'
25
89
26 @task()
90 @task
27 def get_commits_stats(repo):
91 def get_commits_stats(repo):
92 log = get_commits_stats.get_logger()
28 aggregate = OrderedDict()
93 aggregate = OrderedDict()
29 repo = MercurialRepository('/home/marcink/hg_repos/'+repo)
94 repos_path = get_hg_ui_settings()['paths_root_path'].replace('*','')
95 repo = MercurialRepository(repos_path + repo)
30 #graph range
96 #graph range
31 td = datetime.today() + timedelta(days=1)
97 td = datetime.today() + timedelta(days=1)
32 y, m, d = td.year, td.month, td.day
98 y, m, d = td.year, td.month, td.day
@@ -90,3 +156,60 b' def get_commits_stats(repo):'
90 % (author_key_cleaner(repo.contact),
156 % (author_key_cleaner(repo.contact),
91 author_key_cleaner(repo.contact))
157 author_key_cleaner(repo.contact))
92 return (ts_min, ts_max, d)
158 return (ts_min, ts_max, d)
159
160 @task
161 def reset_user_password(user_email):
162 log = reset_user_password.get_logger()
163 from pylons_app.lib import auth
164 from pylons_app.model.db import User
165
166 try:
167
168 try:
169 sa = get_session()
170 user = sa.query(User).filter(User.email == user_email).scalar()
171 new_passwd = auth.PasswordGenerator().gen_password(8,
172 auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
173 user.password = auth.get_crypt_password(new_passwd)
174 sa.add(user)
175 sa.commit()
176 log.info('change password for %s', user_email)
177 if new_passwd is None:
178 raise Exception('unable to generate new password')
179
180 except:
181 log.error(traceback.format_exc())
182 sa.rollback()
183
184 run_task(send_email, user_email,
185 "Your new hg-app password",
186 'Your new hg-app password:%s' % (new_passwd))
187 log.info('send new password mail to %s', user_email)
188
189
190 except:
191 log.error('Failed to update user password')
192 log.error(traceback.format_exc())
193 return True
194
195 @task
196 def send_email(recipients, subject, body):
197 log = send_email.get_logger()
198 email_config = dict(config.items('DEFAULT'))
199 mail_from = email_config.get('app_email_from')
200 user = email_config.get('smtp_username')
201 passwd = email_config.get('smtp_password')
202 mail_server = email_config.get('smtp_server')
203 mail_port = email_config.get('smtp_port')
204 tls = email_config.get('smtp_use_tls')
205 ssl = False
206
207 try:
208 m = SmtpMailer(mail_from, user, passwd, mail_server,
209 mail_port, ssl, tls)
210 m.send(recipients, subject, body)
211 except:
212 log.error('Mail sending failed')
213 log.error(traceback.format_exc())
214 return False
215 return True
@@ -102,7 +102,7 b' class ValidAuth(formencode.validators.Fa'
102 error_dict=self.e_dict)
102 error_dict=self.e_dict)
103 if user:
103 if user:
104 if user.active:
104 if user.active:
105 if user.username == username and check_password(password,
105 if user.username == username and check_password(password,
106 user.password):
106 user.password):
107 return value
107 return value
108 else:
108 else:
@@ -208,7 +208,20 b' class ValidPath(formencode.validators.Fa'
208
208
209 raise formencode.Invalid(msg, value, state,
209 raise formencode.Invalid(msg, value, state,
210 error_dict={'paths_root_path':msg})
210 error_dict={'paths_root_path':msg})
211
211
212 class ValidSystemEmail(formencode.validators.FancyValidator):
213 def to_python(self, value, state):
214 sa = meta.Session
215 try:
216 user = sa.query(User).filter(User.email == value).scalar()
217 if user is None:
218 raise formencode.Invalid(_("That e-mail address doesn't exist.") ,
219 value, state)
220 finally:
221 meta.Session.remove()
222
223 return value
224
212 #===============================================================================
225 #===============================================================================
213 # FORMS
226 # FORMS
214 #===============================================================================
227 #===============================================================================
@@ -255,8 +268,14 b' def UserForm(edit=False, old_data={}):'
255 return _UserForm
268 return _UserForm
256
269
257 RegisterForm = UserForm
270 RegisterForm = UserForm
258
271
259
272 def PasswordResetForm():
273 class _PasswordResetForm(formencode.Schema):
274 allow_extra_fields = True
275 filter_extra_fields = True
276 email = All(ValidSystemEmail(), Email(not_empty=True))
277 return _PasswordResetForm
278
260 def RepoForm(edit=False, old_data={}):
279 def RepoForm(edit=False, old_data={}):
261 class _RepoForm(formencode.Schema):
280 class _RepoForm(formencode.Schema):
262 allow_extra_fields = True
281 allow_extra_fields = True
@@ -2,7 +2,7 b''
2 # encoding: utf-8
2 # encoding: utf-8
3 # Model for users
3 # Model for users
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
4 # Copyright (C) 2009-2010 Marcin Kuzminski <marcin@python-works.com>
5
5 #
6 # This program is free software; you can redistribute it and/or
6 # This program is free software; you can redistribute it and/or
7 # modify it under the terms of the GNU General Public License
7 # modify it under the terms of the GNU General Public License
8 # as published by the Free Software Foundation; version 2
8 # as published by the Free Software Foundation; version 2
@@ -23,10 +23,12 b' Created on April 9, 2010'
23 Model for users
23 Model for users
24 @author: marcink
24 @author: marcink
25 """
25 """
26
26 from pylons_app.lib import auth
27 from pylons.i18n.translation import _
28 from pylons_app.lib.celerylib import tasks, run_task
27 from pylons_app.model.db import User
29 from pylons_app.model.db import User
28 from pylons_app.model.meta import Session
30 from pylons_app.model.meta import Session
29 from pylons.i18n.translation import _
31 import traceback
30 import logging
32 import logging
31 log = logging.getLogger(__name__)
33 log = logging.getLogger(__name__)
32
34
@@ -43,7 +45,7 b' class UserModel(object):'
43 def get_user(self, id):
45 def get_user(self, id):
44 return self.sa.query(User).get(id)
46 return self.sa.query(User).get(id)
45
47
46 def get_user_by_name(self,name):
48 def get_user_by_name(self, name):
47 return self.sa.query(User).filter(User.username == name).scalar()
49 return self.sa.query(User).filter(User.username == name).scalar()
48
50
49 def create(self, form_data):
51 def create(self, form_data):
@@ -54,8 +56,8 b' class UserModel(object):'
54
56
55 self.sa.add(new_user)
57 self.sa.add(new_user)
56 self.sa.commit()
58 self.sa.commit()
57 except Exception as e:
59 except:
58 log.error(e)
60 log.error(traceback.format_exc())
59 self.sa.rollback()
61 self.sa.rollback()
60 raise
62 raise
61
63
@@ -68,8 +70,8 b' class UserModel(object):'
68
70
69 self.sa.add(new_user)
71 self.sa.add(new_user)
70 self.sa.commit()
72 self.sa.commit()
71 except Exception as e:
73 except:
72 log.error(e)
74 log.error(traceback.format_exc())
73 self.sa.rollback()
75 self.sa.rollback()
74 raise
76 raise
75
77
@@ -88,8 +90,8 b' class UserModel(object):'
88
90
89 self.sa.add(new_user)
91 self.sa.add(new_user)
90 self.sa.commit()
92 self.sa.commit()
91 except Exception as e:
93 except:
92 log.error(e)
94 log.error(traceback.format_exc())
93 self.sa.rollback()
95 self.sa.rollback()
94 raise
96 raise
95
97
@@ -109,13 +111,12 b' class UserModel(object):'
109
111
110 self.sa.add(new_user)
112 self.sa.add(new_user)
111 self.sa.commit()
113 self.sa.commit()
112 except Exception as e:
114 except:
113 log.error(e)
115 log.error(traceback.format_exc())
114 self.sa.rollback()
116 self.sa.rollback()
115 raise
117 raise
116
118
117 def delete(self, id):
119 def delete(self, id):
118
119 try:
120 try:
120
121
121 user = self.sa.query(User).get(id)
122 user = self.sa.query(User).get(id)
@@ -125,7 +126,10 b' class UserModel(object):'
125 " crucial for entire application"))
126 " crucial for entire application"))
126 self.sa.delete(user)
127 self.sa.delete(user)
127 self.sa.commit()
128 self.sa.commit()
128 except Exception as e:
129 except:
129 log.error(e)
130 log.error(traceback.format_exc())
130 self.sa.rollback()
131 self.sa.rollback()
131 raise
132 raise
133
134 def reset_password(self, data):
135 run_task(tasks.reset_user_password, data['email'])
@@ -60,7 +60,7 b''
60 <!-- end fields -->
60 <!-- end fields -->
61 <!-- links -->
61 <!-- links -->
62 <div class="links">
62 <div class="links">
63 ${h.link_to(_('Forgot your password ?'),h.url('#'))}
63 ${h.link_to(_('Forgot your password ?'),h.url('reset_password'))}
64 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
64 %if h.HasPermissionAny('hg.admin', 'hg.register.auto_activate', 'hg.register.manual_activate')():
65 /
65 /
66 ${h.link_to(_("Don't have an account ?"),h.url('register'))}
66 ${h.link_to(_("Don't have an account ?"),h.url('register'))}
General Comments 0
You need to be logged in to leave comments. Login now