@@ -13,24 +13,25 @@ debug = true
## Additionally those settings will be used by rhodecode mailing system ##
################################################################################
#email_to = admin@localhost
#error_email_from = paste_error@localhost
#app_email_from = rhodecode-noreply@localhost
#error_message =
#smtp_server = mail.server.com
#smtp_username =
#smtp_password =
#smtp_port =
#smtp_use_tls = false
#smtp_use_ssl = true
[server:main]
##nr of threads to spawn
threadpool_workers = 5
##max request before thread respawn
threadpool_max_requests = 2
##option to use threads of process
use_threadpool = true
use = egg:Paste#http
threadpool_max_requests = 10
@@ -221,33 +221,49 @@ def reset_user_password(user_email):
"Your new rhodecode password",
'Your new rhodecode password:%s' % (new_passwd))
log.info('send new password mail to %s', user_email)
except:
log.error('Failed to update user password')
log.error(traceback.format_exc())
return True
@task
def send_email(recipients, subject, body):
"""
Sends an email with defined parameters from the .ini files.
:param recipients: list of recipients, it this is empty the defined email
address from field 'email_to' is used instead
:param subject: subject of the mail
:param body: body of the mail
log = send_email.get_logger()
email_config = dict(config.items('DEFAULT'))
if not recipients:
recipients = [email_config.get('email_to')]
def str2bool(v):
return v.lower() in ["yes", "true", "t", "1"]
mail_from = email_config.get('app_email_from')
user = email_config.get('smtp_username')
passwd = email_config.get('smtp_password')
mail_server = email_config.get('smtp_server')
mail_port = email_config.get('smtp_port')
tls = email_config.get('smtp_use_tls')
ssl = False
tls = str2bool(email_config.get('smtp_use_tls'))
ssl = str2bool(email_config.get('smtp_use_ssl'))
try:
m = SmtpMailer(mail_from, user, passwd, mail_server,
mail_port, ssl, tls)
m.send(recipients, subject, body)
log.error('Mail sending failed')
return False
@@ -13,50 +13,50 @@ class SmtpMailer(object):
"""simple smtp mailer class
mailer = SmtpMailer(mail_from, user, passwd, mail_server, mail_port, ssl, tls)
mailer.send(recipients, subject, body, attachment_files)
:param recipients might be a list of string or single string
:param attachment_files is a dict of {filename:location}
it tries to guess the mimetype and attach the file
def __init__(self, mail_from, user, passwd, mail_server,
mail_port=None, ssl=False, tls=False):
self.mail_from = mail_from
self.mail_server = mail_server
self.mail_port = mail_port
self.user = user
self.passwd = passwd
self.ssl = ssl
self.tls = tls
self.debug = False
def send(self, recipients=[], subject='', body='', attachment_files={}):
if isinstance(recipients, basestring):
recipients = [recipients]
if self.ssl:
smtp_serv = smtplib.SMTP_SSL(self.mail_server, self.mail_port)
else:
smtp_serv = smtplib.SMTP(self.mail_server, self.mail_port)
if self.tls:
smtp_serv.starttls()
if self.debug:
smtp_serv.set_debuglevel(1)
smtp_serv.ehlo("mailer")
smtp_serv.ehlo("rhodecode mailer")
#if server requires authorization you must provide login and password
smtp_serv.login(self.user, self.passwd)
date_ = formatdate(localtime=True)
msg = MIMEMultipart()
msg['From'] = self.mail_from
msg['To'] = ','.join(recipients)
msg['Date'] = date_
msg['Subject'] = subject
msg.preamble = 'You will not see this in a MIME-aware mail reader.\n'
@@ -73,45 +73,45 @@ class SmtpMailer(object):
def __atach_files(self, msg, attachment_files):
if isinstance(attachment_files, dict):
for f_name, msg_file in attachment_files.items():
ctype, encoding = mimetypes.guess_type(f_name)
logging.info("guessing file %s type based on %s" , ctype, f_name)
if ctype is None or encoding is not None:
# No guess could be made, or the file is encoded (compressed), so
# use a generic bag-of-bits type.
ctype = 'application/octet-stream'
maintype, subtype = ctype.split('/', 1)
if maintype == 'text':
# Note: we should handle calculating the charset
file_part = MIMEText(self.get_content(msg_file),
_subtype=subtype)
elif maintype == 'image':
file_part = MIMEImage(self.get_content(msg_file),
elif maintype == 'audio':
file_part = MIMEAudio(self.get_content(msg_file),
file_part = MIMEBase(maintype, subtype)
file_part.set_payload(self.get_content(msg_file))
# Encode the payload using Base64
encoders.encode_base64(msg)
# Set the filename parameter
file_part.add_header('Content-Disposition', 'attachment',
filename=f_name)
file_part.add_header('Content-Type', ctype, name=f_name)
msg.attach(file_part)
raise Exception('Attachment files should be'
'a dict in format {"filename":"filepath"}')
def get_content(self, msg_file):
'''
Get content based on type, if content is a string do open first
else just read because it's a probably open file object
:param msg_file:
if isinstance(msg_file, str):
return open(msg_file, "rb").read()
#just for safe seek to 0
msg_file.seek(0)
@@ -59,46 +59,65 @@ def is_mercurial(environ):
def is_git(environ):
Returns True if request's target is git server. ``HTTP_USER_AGENT`` would
then have git client version given.
:param environ:
http_user_agent = environ.get('HTTP_USER_AGENT')
if http_user_agent and http_user_agent.startswith('git'):
def action_logger(user, action, repo, ipaddr, sa=None):
def action_logger(user, action, repo, ipaddr='', sa=None):
Action logger for various action made by users
:param user: user that made this action, can be a string unique username or
object containing user_id attribute
:param action: action to log, should be on of predefined unique actions for
easy translations
:param repo: repository that action was made on
:param ipaddr: optional ip address from what the action was made
:param sa: optional sqlalchemy session
if not sa:
sa = meta.Session()
if hasattr(user, 'user_id'):
user_obj = user
elif isinstance(user, basestring):
user_obj = UserModel(sa).get_by_username(user, cache=False)
raise Exception('You have to provide user object or username')
repo_name = repo.lstrip('/')
if repo:
repository = RepoModel(sa).get(repo_name, cache=False)
if not repository:
raise Exception('You have to provide valid repository')
raise Exception('You have to provide repository to action logger')
user_log = UserLog()
user_log.user_id = user_obj.user_id
user_log.action = action
user_log.repository_name = repo_name
user_log.repository = RepoModel(sa).get(repo_name, cache=False)
user_log.repository = repository
user_log.action_date = datetime.datetime.now()
user_log.user_ip = ipaddr
sa.add(user_log)
sa.commit()
log.info('Adding user %s, action %s on %s',
user_obj.username, action, repo)
sa.rollback()
def get_repos(path, recursive=False, initial=False):
@@ -63,32 +63,41 @@ class UserModel(object):
new_user = User()
for k, v in form_data.items():
setattr(new_user, k, v)
self.sa.add(new_user)
self.sa.commit()
self.sa.rollback()
raise
def create_registration(self, form_data):
from rhodecode.lib.celerylib import tasks, run_task
if k != 'admin':
body = ('New user registration\n'
'username: %s\n'
'email: %s\n')
body = body % (form_data['username'], form_data['email'])
run_task(tasks.send_email, None,
_('[RhodeCode] New User registration'),
body)
def update(self, user_id, form_data):
new_user = self.get(user_id, cache=False)
if new_user.username == 'default':
raise DefaultUserException(
_("You can't Edit this user since it's"
" crucial for entire application"))
Status change: