##// END OF EJS Templates
#302 - basic notification system, models+tests
#302 - basic notification system, models+tests

File last commit:

r1673:333b3e7c beta
r1702:8cb7f5c4 beta
Show More
tasks.py
414 lines | 13.6 KiB | text/x-python | PythonLexer
code docs, updates
r903 # -*- coding: utf-8 -*-
"""
rhodecode.lib.celerylib.tasks
made rhodecode work with celery 2.2, made some tasks optimizations(forget results)...
r1002 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
code docs, updates
r903
RhodeCode task modules, containing all task that suppose to be run
by celery daemon
source code cleanup: remove trailing white space, normalize file endings
r1203
code docs, updates
r903 :created_on: Oct 6, 2010
:author: marcink
source code cleanup: remove trailing white space, normalize file endings
r1203 :copyright: (C) 2009-2011 Marcin Kuzminski <marcin@python-works.com>
code docs, updates
r903 :license: GPLv3, see COPYING for more details.
"""
fixed license issue #149
r1206 # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
source code cleanup: remove trailing white space, normalize file endings
r1203 #
code docs, updates
r903 # This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
source code cleanup: remove trailing white space, normalize file endings
r1203 #
code docs, updates
r903 # You should have received a copy of the GNU General Public License
fixed license issue #149
r1206 # along with this program. If not, see <http://www.gnu.org/licenses/>.
renamed project to rhodecode
r547 from celery.decorators import task
added fault tolerant case when celeryconfig is not present in the directory....
r555
#50 on point cache invalidation changes....
r692 import os
import traceback
made rhodecode work with celery 2.2, made some tasks optimizations(forget results)...
r1002 import logging
fixes issue #197 Relative paths for pidlocks
r1354 from os.path import dirname as dn, join as jn
made rhodecode work with celery 2.2, made some tasks optimizations(forget results)...
r1002
#50 on point cache invalidation changes....
r692 from time import mktime
renamed project to rhodecode
r547 from operator import itemgetter
fixed issue #165 trending source files are now stored in cache as ext only, and translated to description only when displaying, so future changes of mappings will take affect right away....
r1244 from string import lower
Celery is configured by the .ini files and run from paster now...
r776
fixes #223 improve password reset form
r1417 from pylons import config, url
renamed project to rhodecode
r547 from pylons.i18n.translation import _
Celery is configured by the .ini files and run from paster now...
r776
Unicode fixes, added safe_str method for global str() operations +better test sandboxing
r1401 from rhodecode.lib import LANGUAGES_EXTENSIONS_MAP, safe_str
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 from rhodecode.lib.celerylib import run_task, locked_task, str2bool, \
__get_lockkey, LockHeld, DaemonLock
renamed project to rhodecode
r547 from rhodecode.lib.helpers import person
from rhodecode.lib.smtp_mailer import SmtpMailer
Changed OrderedDict implementation to pypy odict, in general it's the fastest and most reliable solution. Added OrderedTuple from python foundation.
r1337 from rhodecode.lib.utils import add_cache
fixed issues with python2.5...
r1514 from rhodecode.lib.compat import json, OrderedDict
Celery is configured by the .ini files and run from paster now...
r776 from rhodecode.model import init_model
from rhodecode.model import meta
implements #291 email notification sent to all admin users
r1612 from rhodecode.model.db import RhodeCodeUi, Statistics, Repository, User
Celery is configured by the .ini files and run from paster now...
r776
Hacking for git support,and new faster repo scan
r631 from vcs.backends import get_repo
Celery is configured by the .ini files and run from paster now...
r776
from sqlalchemy import engine_from_config
#50 on point cache invalidation changes....
r692
fixed cache problem,...
r777 add_cache(config)
fixed issues with python2.5...
r1514
refactor codes and setup for python 2.5...
r564
renamed project to rhodecode
r547 __all__ = ['whoosh_index', 'get_commits_stats',
'reset_user_password', 'send_email']
Celery is configured by the .ini files and run from paster now...
r776 CELERY_ON = str2bool(config['app_conf'].get('use_celery'))
fixed issue #165 trending source files are now stored in cache as ext only, and translated to description only when displaying, so future changes of mappings will take affect right away....
r1244
renamed project to rhodecode
r547 def get_session():
Celery is configured by the .ini files and run from paster now...
r776 if CELERY_ON:
engine = engine_from_config(config, 'sqlalchemy.db1.')
init_model(engine)
sa = meta.Session()
renamed project to rhodecode
r547 return sa
fixed issue #165 trending source files are now stored in cache as ext only, and translated to description only when displaying, so future changes of mappings will take affect right away....
r1244
#50 on point cache invalidation changes....
r692 def get_repos_path():
sa = get_session()
q = sa.query(RhodeCodeUi).filter(RhodeCodeUi.ui_key == '/').one()
return q.ui_value
fixed issue #165 trending source files are now stored in cache as ext only, and translated to description only when displaying, so future changes of mappings will take affect right away....
r1244
made rhodecode work with celery 2.2, made some tasks optimizations(forget results)...
r1002 @task(ignore_result=True)
renamed project to rhodecode
r547 @locked_task
def whoosh_index(repo_location, full_index):
made rhodecode work with celery 2.2, made some tasks optimizations(forget results)...
r1002 #log = whoosh_index.get_logger()
renamed project to rhodecode
r547 from rhodecode.lib.indexers.daemon import WhooshIndexingDaemon
Celery is configured by the .ini files and run from paster now...
r776 index_location = config['index_dir']
fixed annotation bug, added history to annotation....
r662 WhooshIndexingDaemon(index_location=index_location,
fixed cache problem,...
r777 repo_location=repo_location, sa=get_session())\
.run(full_index=full_index)
renamed project to rhodecode
r547
fixed issue #165 trending source files are now stored in cache as ext only, and translated to description only when displaying, so future changes of mappings will take affect right away....
r1244
made rhodecode work with celery 2.2, made some tasks optimizations(forget results)...
r1002 @task(ignore_result=True)
renamed project to rhodecode
r547 def get_commits_stats(repo_name, ts_min_y, ts_max_y):
made rhodecode work with celery 2.2, made some tasks optimizations(forget results)...
r1002 try:
log = get_commits_stats.get_logger()
except:
log = logging.getLogger(__name__)
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 lockkey = __get_lockkey('get_commits_stats', repo_name, ts_min_y,
ts_max_y)
fixes #258 RhodeCode 1.2 assumes egg folder is writable
r1540 lockkey_path = config['here']
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 log.info('running task with lockkey %s', lockkey)
try:
fixes #258 RhodeCode 1.2 assumes egg folder is writable
r1540 lock = l = DaemonLock(file_=jn(lockkey_path, lockkey))
Code refactor for auth func, preparing for ldap support...
r699
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 #for js data compatibilty cleans the key for person from '
akc = lambda k: person(k).replace('"', "")
Code refactoring,models renames...
r629
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 co_day_auth_aggr = {}
commits_by_day_aggregate = {}
repos_path = get_repos_path()
Unicode fixes, added safe_str method for global str() operations +better test sandboxing
r1401 repo = get_repo(safe_str(os.path.join(repos_path, repo_name)))
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 repo_size = len(repo.revisions)
#return if repo have no revisions
if repo_size < 1:
lock.release()
return True
renamed project to rhodecode
r547
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 skip_date_limit = True
parse_limit = int(config['app_conf'].get('commit_parse_limit'))
last_rev = 0
last_cs = None
timegetter = itemgetter('time')
Code refactoring,models renames...
r629
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 sa = get_session()
Code refactoring,models renames...
r629
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 dbrepo = sa.query(Repository)\
.filter(Repository.repo_name == repo_name).scalar()
cur_stats = sa.query(Statistics)\
.filter(Statistics.repository == dbrepo).scalar()
Added branch filter to repo pager...
r1105
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 if cur_stats is not None:
last_rev = cur_stats.stat_on_revision
Added branch filter to repo pager...
r1105
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 if last_rev == repo.get_changeset().revision and repo_size > 1:
#pass silently without any work if we're not on first revision or
#current state of parsing revision(from db marker) is the
#last revision
lock.release()
return True
Code refactoring,models renames...
r629
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 if cur_stats:
commits_by_day_aggregate = OrderedDict(json.loads(
cur_stats.commit_activity_combined))
co_day_auth_aggr = json.loads(cur_stats.commit_activity)
Code refactoring,models renames...
r629
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 log.debug('starting parsing %s', parse_limit)
lmktime = mktime
last_rev = last_rev + 1 if last_rev > 0 else last_rev
Code refactoring,models renames...
r629
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 for cs in repo[last_rev:last_rev + parse_limit]:
last_cs = cs # remember last parsed changeset
k = lmktime([cs.date.timetuple()[0], cs.date.timetuple()[1],
cs.date.timetuple()[2], 0, 0, 0, 0, 0, 0])
moved statistics parse_limit into .ini files...
r1076
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 if akc(cs.author) in co_day_auth_aggr:
try:
l = [timegetter(x) for x in
co_day_auth_aggr[akc(cs.author)]['data']]
time_pos = l.index(k)
except ValueError:
time_pos = False
if time_pos >= 0 and time_pos is not False:
datadict = \
co_day_auth_aggr[akc(cs.author)]['data'][time_pos]
code stats speed improvments
r804
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 datadict["commits"] += 1
datadict["added"] += len(cs.added)
datadict["changed"] += len(cs.changed)
datadict["removed"] += len(cs.removed)
else:
if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
Code refactoring,models renames...
r629
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 datadict = {"time": k,
"commits": 1,
"added": len(cs.added),
"changed": len(cs.changed),
"removed": len(cs.removed),
}
co_day_auth_aggr[akc(cs.author)]['data']\
.append(datadict)
Code refactoring,models renames...
r629
renamed project to rhodecode
r547 else:
if k >= ts_min_y and k <= ts_max_y or skip_date_limit:
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 co_day_auth_aggr[akc(cs.author)] = {
"label": akc(cs.author),
"data": [{"time":k,
"commits":1,
"added":len(cs.added),
"changed":len(cs.changed),
"removed":len(cs.removed),
}],
"schema": ["commits"],
}
Code refactoring,models renames...
r629
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 #gather all data by day
if k in commits_by_day_aggregate:
commits_by_day_aggregate[k] += 1
else:
commits_by_day_aggregate[k] = 1
Code refactoring,models renames...
r629
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 overview_data = sorted(commits_by_day_aggregate.items(),
key=itemgetter(0))
if not co_day_auth_aggr:
co_day_auth_aggr[akc(repo.contact)] = {
"label": akc(repo.contact),
"data": [0, 1],
"schema": ["commits"],
}
Code refactoring,models renames...
r629
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 stats = cur_stats if cur_stats else Statistics()
stats.commit_activity = json.dumps(co_day_auth_aggr)
stats.commit_activity_combined = json.dumps(overview_data)
renamed project to rhodecode
r547
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 log.debug('last revison %s', last_rev)
leftovers = len(repo.revisions[last_rev:])
log.debug('revisions to parse %s', leftovers)
renamed project to rhodecode
r547
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 if last_rev == 0 or leftovers < parse_limit:
log.debug('getting code trending stats')
stats.languages = json.dumps(__get_codes_stats(repo_name))
Code refactoring,models renames...
r629
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 try:
stats.repository = dbrepo
stats.stat_on_revision = last_cs.revision if last_cs else 0
sa.add(stats)
sa.commit()
except:
log.error(traceback.format_exc())
sa.rollback()
lock.release()
return False
Code refactoring,models renames...
r629
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 #final release
lock.release()
Code refactoring,models renames...
r629
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 #execute another task if celery is enabled
if len(repo.revisions) > 1 and CELERY_ON:
run_task(get_commits_stats, repo_name, ts_min_y, ts_max_y)
return True
except LockHeld:
log.info('LockHeld')
return 'Task with key %s already running' % lockkey
renamed project to rhodecode
r547
fixes #223 improve password reset form
r1417 @task(ignore_result=True)
def send_password_link(user_email):
try:
log = reset_user_password.get_logger()
except:
log = logging.getLogger(__name__)
from rhodecode.lib import auth
from rhodecode.model.db import User
try:
sa = get_session()
user = sa.query(User).filter(User.email == user_email).scalar()
if user:
link = url('reset_password_confirmation', key=user.api_key,
qualified=True)
tmpl = """
Hello %s
We received a request to create a new password for your account.
You can generate it by clicking following URL:
%s
If you didn't request new password please ignore this email.
"""
run_task(send_email, user_email,
"RhodeCode password reset link",
tmpl % (user.short_contact, link))
log.info('send new password mail to %s', user_email)
except:
log.error('Failed to update user password')
log.error(traceback.format_exc())
return False
return True
fixed issue #165 trending source files are now stored in cache as ext only, and translated to description only when displaying, so future changes of mappings will take affect right away....
r1244
made rhodecode work with celery 2.2, made some tasks optimizations(forget results)...
r1002 @task(ignore_result=True)
renamed project to rhodecode
r547 def reset_user_password(user_email):
made rhodecode work with celery 2.2, made some tasks optimizations(forget results)...
r1002 try:
log = reset_user_password.get_logger()
except:
log = logging.getLogger(__name__)
renamed project to rhodecode
r547 from rhodecode.lib import auth
from rhodecode.model.db import User
Code refactoring,models renames...
r629
renamed project to rhodecode
r547 try:
try:
sa = get_session()
user = sa.query(User).filter(User.email == user_email).scalar()
new_passwd = auth.PasswordGenerator().gen_password(8,
auth.PasswordGenerator.ALPHABETS_BIG_SMALL)
if user:
user.password = auth.get_crypt_password(new_passwd)
Added api_key into user, api key get's generated again after password change...
r1116 user.api_key = auth.generate_api_key(user.username)
renamed project to rhodecode
r547 sa.add(user)
sa.commit()
log.info('change password for %s', user_email)
if new_passwd is None:
raise Exception('unable to generate new password')
Code refactoring,models renames...
r629
renamed project to rhodecode
r547 except:
log.error(traceback.format_exc())
sa.rollback()
Code refactoring,models renames...
r629
renamed project to rhodecode
r547 run_task(send_email, user_email,
fixes #223 improve password reset form
r1417 "Your new RhodeCode password",
'Your new RhodeCode password:%s' % (new_passwd))
renamed project to rhodecode
r547 log.info('send new password mail to %s', user_email)
Code refactoring,models renames...
r629
renamed project to rhodecode
r547 except:
log.error('Failed to update user password')
log.error(traceback.format_exc())
Celery is configured by the .ini files and run from paster now...
r776
renamed project to rhodecode
r547 return True
fixed issue #165 trending source files are now stored in cache as ext only, and translated to description only when displaying, so future changes of mappings will take affect right away....
r1244
made rhodecode work with celery 2.2, made some tasks optimizations(forget results)...
r1002 @task(ignore_result=True)
renamed project to rhodecode
r547 def send_email(recipients, subject, body):
fixes #59, notifications for user registrations + some changes to mailer
r689 """
Sends an email with defined parameters from the .ini files.
source code cleanup: remove trailing white space, normalize file endings
r1203
fixes #59, notifications for user registrations + some changes to mailer
r689 :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
"""
made rhodecode work with celery 2.2, made some tasks optimizations(forget results)...
r1002 try:
log = send_email.get_logger()
except:
log = logging.getLogger(__name__)
Celery is configured by the .ini files and run from paster now...
r776 email_config = config
fixes #59, notifications for user registrations + some changes to mailer
r689
if not recipients:
implements #291 email notification sent to all admin users
r1612 # if recipients are not defined we send to email_config + all admins
Added email sending test site
r1673 admins = [u.email for u in User.query().filter(User.admin == True).all()]
implements #291 email notification sent to all admin users
r1612 recipients = [email_config.get('email_to')] + admins
fixes #59, notifications for user registrations + some changes to mailer
r689
renamed project to rhodecode
r547 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')
fixes #59, notifications for user registrations + some changes to mailer
r689 tls = str2bool(email_config.get('smtp_use_tls'))
ssl = str2bool(email_config.get('smtp_use_ssl'))
control mailer debug with the .ini file
r1169 debug = str2bool(config.get('debug'))
Les Peabody
applied smth_auth options update patch
r1581 smtp_auth = email_config.get('smtp_auth')
Code refactoring,models renames...
r629
renamed project to rhodecode
r547 try:
Added email sending test site
r1673 m = SmtpMailer(mail_from, user, passwd, mail_server, smtp_auth,
control mailer debug with the .ini file
r1169 mail_port, ssl, tls, debug=debug)
Code refactoring,models renames...
r629 m.send(recipients, subject, body)
renamed project to rhodecode
r547 except:
log.error('Mail sending failed')
log.error(traceback.format_exc())
return False
return True
fixed issue #165 trending source files are now stored in cache as ext only, and translated to description only when displaying, so future changes of mappings will take affect right away....
r1244
made rhodecode work with celery 2.2, made some tasks optimizations(forget results)...
r1002 @task(ignore_result=True)
renamed project to rhodecode
r547 def create_repo_fork(form_data, cur_user):
moved locking of commit stats into the task itself to remove race conditions when lock was not removed before starting another task.
r1264 from rhodecode.model.repo import RepoModel
from vcs import get_backend
made rhodecode work with celery 2.2, made some tasks optimizations(forget results)...
r1002 try:
log = create_repo_fork.get_logger()
except:
log = logging.getLogger(__name__)
fixed Example celery config to ampq,...
r752 repo_model = RepoModel(get_session())
some small fixes
r630 repo_model.create(form_data, cur_user, just_db=True, fork=True)
extended repo creation by repo type. fixed fork creation to maintain repo type.
r659 repo_name = form_data['repo_name']
#50 on point cache invalidation changes....
r692 repos_path = get_repos_path()
extended repo creation by repo type. fixed fork creation to maintain repo type.
r659 repo_path = os.path.join(repos_path, repo_name)
renamed project to rhodecode
r547 repo_fork_path = os.path.join(repos_path, form_data['fork_name'])
extended repo creation by repo type. fixed fork creation to maintain repo type.
r659 alias = form_data['repo_type']
Code refactoring,models renames...
r629
extended repo creation by repo type. fixed fork creation to maintain repo type.
r659 log.info('creating repo fork %s as %s', repo_name, repo_path)
backend = get_backend(alias)
backend(str(repo_fork_path), create=True, src_url=str(repo_path))
Code refactoring,models renames...
r629
fixed issue #165 trending source files are now stored in cache as ext only, and translated to description only when displaying, so future changes of mappings will take affect right away....
r1244
renamed project to rhodecode
r547 def __get_codes_stats(repo_name):
#50 on point cache invalidation changes....
r692 repos_path = get_repos_path()
Unicode fixes, added safe_str method for global str() operations +better test sandboxing
r1401 repo = get_repo(safe_str(os.path.join(repos_path, repo_name)))
removed soon deprecated walk method on repository instance
r603 tip = repo.get_changeset()
renamed project to rhodecode
r547 code_stats = {}
some small fixes
r630
def aggregate(cs):
for f in cs[2]:
fixed issue #165 trending source files are now stored in cache as ext only, and translated to description only when displaying, so future changes of mappings will take affect right away....
r1244 ext = lower(f.extension)
removed binary files from trending sources
r789 if ext in LANGUAGES_EXTENSIONS_MAP.keys() and not f.is_binary:
fixed issue #165 trending source files are now stored in cache as ext only, and translated to description only when displaying, so future changes of mappings will take affect right away....
r1244 if ext in code_stats:
code_stats[ext] += 1
renamed project to rhodecode
r547 else:
fixed issue #165 trending source files are now stored in cache as ext only, and translated to description only when displaying, so future changes of mappings will take affect right away....
r1244 code_stats[ext] = 1
Code refactoring,models renames...
r629
some small fixes
r630 map(aggregate, tip.walk('/'))
renamed project to rhodecode
r547 return code_stats or {}