def settings_email_update(self): """POST /admin/settings/email: All items in the collection""" # url('admin_settings_email') c.active = 'email' test_email = request.POST.get('test_email') if not test_email: h.flash(_('Please enter email address'), category='error') return redirect(url('admin_settings_email')) email_kwargs = { 'date': datetime.datetime.now(), 'user': c.rhodecode_user, 'rhodecode_version': c.rhodecode_version } (subject, headers, email_body, email_body_plaintext) = EmailNotificationModel().render_email( EmailNotificationModel.TYPE_EMAIL_TEST, **email_kwargs) recipients = [test_email] if test_email else None run_task(tasks.send_email, recipients, subject, email_body_plaintext, email_body) h.flash(_('Send email task created'), category='success') return redirect(url('admin_settings_email'))
def send_password_link(user_email): from rhodecode.model.notification import EmailNotificationModel log = get_logger(send_password_link) DBS = get_session() try: user = User.get_by_email(user_email) if user: log.debug('password reset user found %s' % user) link = url('reset_password_confirmation', key=user.api_key, qualified=True) reg_type = EmailNotificationModel.TYPE_PASSWORD_RESET body = EmailNotificationModel().get_email_tmpl(reg_type, **{'user':user.short_contact, 'reset_url':link}) log.debug('sending email') run_task(send_email, user_email, _("password reset link"), body) log.info('send new password mail to %s' % user_email) else: log.debug("password reset email %s not found" % user_email) except: log.error(traceback.format_exc()) return False return True
def reset_user_password(user_email): from rhodecode.lib import auth log = get_logger(reset_user_password) DBS = get_session() try: try: user = User.get_by_email(user_email) new_passwd = auth.PasswordGenerator().gen_password(8, auth.PasswordGenerator.ALPHABETS_BIG_SMALL) if user: user.password = auth.get_crypt_password(new_passwd) user.api_key = auth.generate_api_key(user.username) DBS.add(user) DBS.commit() log.info('change password for %s' % user_email) if new_passwd is None: raise Exception('unable to generate new password') except: log.error(traceback.format_exc()) DBS.rollback() run_task(send_email, user_email, 'Your new 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
def reset_password(self, data): from rhodecode.lib.celerylib import tasks, run_task from rhodecode.lib import auth user_email = data['email'] try: try: user = User.get_by_email(user_email) new_passwd = auth.PasswordGenerator().gen_password(8, auth.PasswordGenerator.ALPHABETS_BIG_SMALL) if user: user.password = auth.get_crypt_password(new_passwd) user.api_key = auth.generate_api_key(user.username) Session().add(user) Session().commit() log.info('change password for %s' % user_email) if new_passwd is None: raise Exception('unable to generate new password') except Exception: log.error(traceback.format_exc()) Session().rollback() run_task(tasks.send_email, user_email, _('Your new password'), _('Your new RhodeCode password:%s') % (new_passwd)) log.info('send new password mail to %s' % user_email) except Exception: log.error('Failed to update user password') log.error(traceback.format_exc()) return True
def reset_password(self, data): from rhodecode.lib.celerylib import tasks, run_task from rhodecode.lib import auth user_email = data['email'] try: try: user = User.get_by_email(user_email) new_passwd = auth.PasswordGenerator().gen_password( 8, auth.PasswordGenerator.ALPHABETS_BIG_SMALL) if user: user.password = auth.get_crypt_password(new_passwd) user.api_key = auth.generate_api_key(user.username) Session().add(user) Session().commit() log.info('change password for %s' % user_email) if new_passwd is None: raise Exception('unable to generate new password') except Exception: log.error(traceback.format_exc()) Session().rollback() run_task(tasks.send_email, user_email, _('Your new password'), _('Your new RhodeCode password:%s') % (new_passwd)) log.info('send new password mail to %s' % user_email) except Exception: log.error('Failed to update user password') log.error(traceback.format_exc()) return True
def reset_password_link(self, data): from rhodecode.lib.celerylib import tasks, run_task from rhodecode.model.notification import EmailNotificationModel user_email = data['email'] try: user = User.get_by_email(user_email) if user: log.debug('password reset user found %s' % user) link = url('reset_password_confirmation', key=user.api_key, qualified=True) reg_type = EmailNotificationModel.TYPE_PASSWORD_RESET body = EmailNotificationModel().get_email_tmpl(reg_type, **{'user': user.short_contact, 'reset_url': link}) log.debug('sending email') run_task(tasks.send_email, user_email, _("Password reset link"), body, body) log.info('send new password mail to %s' % user_email) else: log.debug("password reset email %s not found" % user_email) except Exception: log.error(traceback.format_exc()) return False return True
def reset_user_password(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: 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) user.api_key = auth.generate_api_key(user.username) 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") except: log.error(traceback.format_exc()) sa.rollback() run_task(send_email, 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
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
def reset_password_link(self, data): from rhodecode.lib.celerylib import tasks, run_task from rhodecode.model.notification import EmailNotificationModel user_email = data['email'] try: user = User.get_by_email(user_email) if user: log.debug('password reset user found %s' % user) link = url('reset_password_confirmation', key=user.api_key, qualified=True) reg_type = EmailNotificationModel.TYPE_PASSWORD_RESET body = EmailNotificationModel().get_email_tmpl( reg_type, **{ 'user': user.short_contact, 'reset_url': link }) log.debug('sending email') run_task(tasks.send_email, user_email, _("Password reset link"), body, body) log.info('send new password mail to %s' % user_email) else: log.debug("password reset email %s not found" % user_email) except Exception: log.error(traceback.format_exc()) return False return True
def reset_password(self, data): from rhodecode.lib.celerylib import tasks, run_task from rhodecode.lib import auth user_email = data['email'] pre_db = True try: user = User.get_by_email(user_email) new_passwd = auth.PasswordGenerator().gen_password( 8, auth.PasswordGenerator.ALPHABETS_BIG_SMALL) if user: user.password = auth.get_crypt_password(new_passwd) user.api_key = auth.generate_api_key(user.username) Session().add(user) Session().commit() log.info('change password for %s' % user_email) if new_passwd is None: raise Exception('unable to generate new password') pre_db = False run_task(tasks.send_email, user_email, _('Your new password'), _('Your new RhodeCode password:%s') % (new_passwd, )) log.info('send new password mail to %s' % user_email) except Exception: log.error('Failed to update user password') log.error(traceback.format_exc()) if pre_db: # we rollback only if local db stuff fails. If it goes into # run_task, we're pass rollback state this wouldn't work then Session().rollback() return True
def create_fork(self, form_data, cur_user): """ Simple wrapper into executing celery task for fork creation :param form_data: :param cur_user: """ from rhodecode.lib.celerylib import tasks, run_task run_task(tasks.create_repo_fork, form_data, cur_user)
def reset_password(self, data): from rhodecode.lib.celerylib import tasks, run_task from rhodecode.model.notification import EmailNotificationModel from rhodecode.lib import auth user_email = data['email'] pre_db = True try: user = User.get_by_email(user_email) new_passwd = auth.PasswordGenerator().gen_password( 12, auth.PasswordGenerator.ALPHABETS_BIG_SMALL) if user: user.password = auth.get_crypt_password(new_passwd) # also force this user to reset his password ! user.update_userdata(force_password_change=True) Session().add(user) Session().commit() log.info('change password for %s', user_email) if new_passwd is None: raise Exception('unable to generate new password') pre_db = False email_kwargs = { 'new_password': new_passwd, 'user': user, 'email': user_email, 'date': datetime.datetime.now() } (subject, headers, email_body, email_body_plaintext) = EmailNotificationModel().render_email( EmailNotificationModel.TYPE_PASSWORD_RESET_CONFIRMATION, **email_kwargs) recipients = [user_email] action_logger_generic( 'sent new password to user: {} with email: {}'.format( user, user_email), namespace='security.password_reset') run_task(tasks.send_email, recipients, subject, email_body_plaintext, email_body) except Exception: log.error('Failed to update user password') log.error(traceback.format_exc()) if pre_db: # we rollback only if local db stuff fails. If it goes into # run_task, we're pass rollback state this wouldn't work then Session().rollback() return True
def create(self, form_data, cur_user): """ Create repository using celery tasks :param form_data: :param cur_user: """ from rhodecode.lib.celerylib import tasks, run_task return run_task(tasks.create_repo, form_data, cur_user)
def create_registration(self, form_data): from rhodecode.lib.celerylib import tasks, run_task try: new_user = User() for k, v in form_data.items(): if k != 'admin': setattr(new_user, k, v) self.sa.add(new_user) self.sa.commit() 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) except: log.error(traceback.format_exc()) self.sa.rollback() raise
def reset_password(self, data): from rhodecode.lib.celerylib import tasks, run_task from rhodecode.lib import auth user_email = data["email"] pre_db = True try: user = User.get_by_email(user_email) new_passwd = auth.PasswordGenerator().gen_password(8, auth.PasswordGenerator.ALPHABETS_BIG_SMALL) if user: user.password = auth.get_crypt_password(new_passwd) user.api_key = auth.generate_api_key(user.username) Session().add(user) Session().commit() log.info("change password for %s" % user_email) if new_passwd is None: raise Exception("unable to generate new password") pre_db = False run_task( tasks.send_email, user_email, _("Your new password"), _("Your new RhodeCode password:%s") % (new_passwd,), ) log.info("send new password mail to %s" % user_email) except Exception: log.error("Failed to update user password") log.error(traceback.format_exc()) if pre_db: # we rollback only if local db stuff fails. If it goes into # run_task, we're pass rollback state this wouldn't work then Session().rollback() return True
def reset_password_link(self, data, pwd_reset_url): from rhodecode.lib.celerylib import tasks, run_task from rhodecode.model.notification import EmailNotificationModel user_email = data['email'] try: user = User.get_by_email(user_email) if user: log.debug('password reset user found %s', user) email_kwargs = { 'password_reset_url': pwd_reset_url, 'user': user, 'email': user_email, 'date': datetime.datetime.now() } (subject, headers, email_body, email_body_plaintext) = EmailNotificationModel().render_email( EmailNotificationModel.TYPE_PASSWORD_RESET, **email_kwargs) recipients = [user_email] action_logger_generic( 'sending password reset email to user: {}'.format( user), namespace='security.password_reset') run_task(tasks.send_email, recipients, subject, email_body_plaintext, email_body) else: log.debug("password reset email %s not found", user_email) except Exception: log.error(traceback.format_exc()) return False return True
def create_fork(self, form_data, cur_user): from rhodecode.lib.celerylib import tasks, run_task run_task(tasks.create_repo_fork, form_data, cur_user)
def create(self, created_by, subject, body, recipients=None, type_=Notification.TYPE_MESSAGE, with_email=True, email_kwargs={}): """ Creates notification of given type :param created_by: int, str or User instance. User who created this notification :param subject: :param body: :param recipients: list of int, str or User objects, when None is given send to all admins :param type_: type of notification :param with_email: send email with this notification :param email_kwargs: additional dict to pass as args to email template """ from rhodecode.lib.celerylib import tasks, run_task if recipients and not getattr(recipients, '__iter__', False): raise Exception('recipients must be a list of iterable') created_by_obj = self.__get_user(created_by) if recipients: recipients_objs = [] for u in recipients: obj = self.__get_user(u) if obj: recipients_objs.append(obj) recipients_objs = set(recipients_objs) log.debug('sending notifications %s to %s' % ( type_, recipients_objs) ) else: # empty recipients means to all admins recipients_objs = User.query().filter(User.admin == True).all() log.debug('sending notifications %s to admins: %s' % ( type_, recipients_objs) ) notif = Notification.create( created_by=created_by_obj, subject=subject, body=body, recipients=recipients_objs, type_=type_ ) if with_email is False: return notif # send email with notification for rec in recipients_objs: email_subject = NotificationModel().make_description(notif, False) type_ = type_ email_body = body kwargs = {'subject': subject, 'body': h.rst_w_mentions(body)} kwargs.update(email_kwargs) email_body_html = EmailNotificationModel()\ .get_email_tmpl(type_, **kwargs) run_task(tasks.send_email, rec.email, email_subject, email_body, email_body_html) return notif
def create(self, created_by, subject, body, recipients=None, type_=Notification.TYPE_MESSAGE, with_email=True, email_kwargs={}): """ Creates notification of given type :param created_by: int, str or User instance. User who created this notification :param subject: :param body: :param recipients: list of int, str or User objects, when None is given send to all admins :param type_: type of notification :param with_email: send email with this notification :param email_kwargs: additional dict to pass as args to email template """ from rhodecode.lib.celerylib import tasks, run_task if recipients and not getattr(recipients, '__iter__', False): raise Exception('recipients must be a list of iterable') created_by_obj = self.__get_user(created_by) if recipients: recipients_objs = [] for u in recipients: obj = self.__get_user(u) if obj: recipients_objs.append(obj) recipients_objs = set(recipients_objs) log.debug('sending notifications %s to %s' % (type_, recipients_objs)) else: # empty recipients means to all admins recipients_objs = User.query().filter(User.admin == True).all() log.debug('sending notifications %s to admins: %s' % (type_, recipients_objs)) notif = Notification.create(created_by=created_by_obj, subject=subject, body=body, recipients=recipients_objs, type_=type_) if with_email is False: return notif # send email with notification for rec in recipients_objs: email_subject = NotificationModel().make_description(notif, False) type_ = type_ email_body = body kwargs = {'subject': subject, 'body': h.rst_w_mentions(body)} kwargs.update(email_kwargs) email_body_html = EmailNotificationModel()\ .get_email_tmpl(type_, **kwargs) run_task(tasks.send_email, rec.email, email_subject, email_body, email_body_html) return notif
def update(self, setting_id): """PUT /admin/settings/setting_id: Update an existing item""" # Forms posted to this method should contain a hidden field: # <input type="hidden" name="_method" value="PUT" /> # Or using helpers: # h.form(url('admin_setting', setting_id=ID), # method='put') # url('admin_setting', setting_id=ID) if setting_id == 'mapping': rm_obsolete = request.POST.get('destroy', False) log.debug('Rescanning directories with destroy=%s' % rm_obsolete) initial = ScmModel().repo_scan() log.debug('invalidating all repositories') for repo_name in initial.keys(): invalidate_cache('get_repo_cached_%s' % repo_name) added, removed = repo2db_mapper(initial, rm_obsolete) _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-' h.flash(_('Repositories successfully ' 'rescanned added: %s ; removed: %s') % (_repr(added), _repr(removed)), category='success') if setting_id == 'whoosh': repo_location = self._get_hg_ui_settings()['paths_root_path'] full_index = request.POST.get('full_index', False) run_task(tasks.whoosh_index, repo_location, full_index) h.flash(_('Whoosh reindex task scheduled'), category='success') if setting_id == 'global': application_form = ApplicationSettingsForm()() try: form_result = application_form.to_python(dict(request.POST)) except formencode.Invalid, errors: return htmlfill.render(render('admin/settings/settings.html'), defaults=errors.value, errors=errors.error_dict or {}, prefix_error=False, encoding="UTF-8") try: sett1 = RhodeCodeSetting.get_by_name_or_create('title') sett1.app_settings_value = form_result['rhodecode_title'] Session().add(sett1) sett2 = RhodeCodeSetting.get_by_name_or_create('realm') sett2.app_settings_value = form_result['rhodecode_realm'] Session().add(sett2) sett3 = RhodeCodeSetting.get_by_name_or_create('ga_code') sett3.app_settings_value = form_result['rhodecode_ga_code'] Session().add(sett3) Session().commit() set_rhodecode_config(config) h.flash(_('Updated application settings'), category='success') except Exception: log.error(traceback.format_exc()) h.flash(_('Error occurred during updating ' 'application settings'), category='error')
category='error') return redirect(url('admin_edit_setting', setting_id='hooks')) if setting_id == 'email': test_email = request.POST.get('test_email') test_email_subj = 'RhodeCode TestEmail' test_email_body = 'RhodeCode Email test' test_email_html_body = EmailNotificationModel()\ .get_email_tmpl(EmailNotificationModel.TYPE_DEFAULT, body=test_email_body) recipients = [test_email] if test_email else None run_task(tasks.send_email, recipients, test_email_subj, test_email_body, test_email_html_body) h.flash(_('Email task created'), category='success') return redirect(url('admin_settings')) @HasPermissionAllDecorator('hg.admin') def delete(self, setting_id): """DELETE /admin/settings/setting_id: Delete an existing item""" # Forms posted to this method should contain a hidden field: # <input type="hidden" name="_method" value="DELETE" /> # Or using helpers: # h.form(url('admin_setting', setting_id=ID), # method='delete') # url('admin_setting', setting_id=ID) if setting_id == 'hooks': hook_id = request.POST.get('hook_id')
def update(self, setting_id): """PUT /admin/settings/setting_id: Update an existing item""" # Forms posted to this method should contain a hidden field: # <input type="hidden" name="_method" value="PUT" /> # Or using helpers: # h.form(url('admin_setting', setting_id=ID), # method='put') # url('admin_setting', setting_id=ID) if setting_id == 'mapping': rm_obsolete = request.POST.get('destroy', False) invalidate_cache = request.POST.get('invalidate', False) log.debug('rescanning repo location with destroy obsolete=%s' % (rm_obsolete,)) if invalidate_cache: log.debug('invalidating all repositories cache') for repo in Repository.get_all(): ScmModel().mark_for_invalidation(repo.repo_name) filesystem_repos = ScmModel().repo_scan() added, removed = repo2db_mapper(filesystem_repos, rm_obsolete) _repr = lambda l: ', '.join(map(safe_unicode, l)) or '-' h.flash(_('Repositories successfully ' 'rescanned added: %s ; removed: %s') % (_repr(added), _repr(removed)), category='success') if setting_id == 'whoosh': repo_location = self._get_hg_ui_settings()['paths_root_path'] full_index = request.POST.get('full_index', False) run_task(tasks.whoosh_index, repo_location, full_index) h.flash(_('Whoosh reindex task scheduled'), category='success') if setting_id == 'global': application_form = ApplicationSettingsForm()() try: form_result = application_form.to_python(dict(request.POST)) except formencode.Invalid, errors: return htmlfill.render( render('admin/settings/settings.html'), defaults=errors.value, errors=errors.error_dict or {}, prefix_error=False, encoding="UTF-8" ) try: sett1 = RhodeCodeSetting.get_by_name_or_create('title') sett1.app_settings_value = form_result['rhodecode_title'] Session().add(sett1) sett2 = RhodeCodeSetting.get_by_name_or_create('realm') sett2.app_settings_value = form_result['rhodecode_realm'] Session().add(sett2) sett3 = RhodeCodeSetting.get_by_name_or_create('ga_code') sett3.app_settings_value = form_result['rhodecode_ga_code'] Session().add(sett3) Session().commit() set_rhodecode_config(config) h.flash(_('Updated application settings'), category='success') except Exception: log.error(traceback.format_exc()) h.flash(_('Error occurred during updating ' 'application settings'), category='error')
def create(self, created_by, notification_subject, notification_body, notification_type=Notification.TYPE_MESSAGE, recipients=None, mention_recipients=None, with_email=True, email_kwargs=None): """ Creates notification of given type :param created_by: int, str or User instance. User who created this notification :param notification_subject: subject of notification itself :param notification_body: body of notification text :param notification_type: type of notification, based on that we pick templates :param recipients: list of int, str or User objects, when None is given send to all admins :param mention_recipients: list of int, str or User objects, that were mentioned :param with_email: send email with this notification :param email_kwargs: dict with arguments to generate email """ from rhodecode.lib.celerylib import tasks, run_task if recipients and not getattr(recipients, '__iter__', False): raise Exception('recipients must be an iterable object') created_by_obj = self._get_user(created_by) # default MAIN body if not given email_kwargs = email_kwargs or {'body': notification_body} mention_recipients = mention_recipients or set() if not created_by_obj: raise Exception('unknown user %s' % created_by) if recipients is None: # recipients is None means to all admins recipients_objs = User.query().filter(User.admin == true()).all() log.debug('sending notifications %s to admins: %s', notification_type, recipients_objs) else: recipients_objs = [] for u in recipients: obj = self._get_user(u) if obj: recipients_objs.append(obj) else: # we didn't find this user, log the error and carry on log.error('cannot notify unknown user %r', u) recipients_objs = set(recipients_objs) if not recipients_objs: raise Exception('no valid recipients specified') log.debug('sending notifications %s to %s', notification_type, recipients_objs) # add mentioned users into recipients final_recipients = set(recipients_objs).union(mention_recipients) notification = Notification.create(created_by=created_by_obj, subject=notification_subject, body=notification_body, recipients=final_recipients, type_=notification_type) if not with_email: # skip sending email, and just create notification return notification # don't send email to person who created this comment rec_objs = set(recipients_objs).difference(set([created_by_obj])) # now notify all recipients in question for recipient in rec_objs.union(mention_recipients): # inject current recipient email_kwargs['recipient'] = recipient email_kwargs['mention'] = recipient in mention_recipients (subject, headers, email_body, email_body_plaintext) = EmailNotificationModel().render_email( notification_type, **email_kwargs) log.debug('Creating notification email task for user:`%s`', recipient) task = run_task(tasks.send_email, recipient.email, subject, email_body_plaintext, email_body) log.debug('Created email task: %s', task) return notification
def create(self, created_by, subject, body, recipients=None, type_=Notification.TYPE_MESSAGE, with_email=True, email_kwargs={}, email_subject=None): """ Creates notification of given type :param created_by: int, str or User instance. User who created this notification :param subject: :param body: :param recipients: list of int, str or User objects, when None is given send to all admins :param type_: type of notification :param with_email: send email with this notification :param email_kwargs: additional dict to pass as args to email template :param email_subject: use given subject as email subject """ from rhodecode.lib.celerylib import tasks, run_task if recipients and not getattr(recipients, '__iter__', False): raise Exception('recipients must be a list or iterable') created_by_obj = self._get_user(created_by) if recipients: recipients_objs = [] for u in recipients: obj = self._get_user(u) if obj: recipients_objs.append(obj) else: # TODO: inform user that requested operation couldn't be completed log.error('cannot email unknown user %r', u) recipients_objs = set(recipients_objs) log.debug('sending notifications %s to %s' % (type_, recipients_objs)) else: # empty recipients means to all admins recipients_objs = User.query().filter(User.admin == True).all() log.debug('sending notifications %s to admins: %s' % (type_, recipients_objs)) # TODO: inform user who are notified notif = Notification.create(created_by=created_by_obj, subject=subject, body=body, recipients=recipients_objs, type_=type_) if not with_email: return notif #don't send email to person who created this comment rec_objs = set(recipients_objs).difference(set([created_by_obj])) # send email with notification to all other participants for rec in rec_objs: if not email_subject: email_subject = NotificationModel()\ .make_description(notif, show_age=False) type_ = type_ email_body = None # we set body to none, we just send HTML emails ## this is passed into template kwargs = {'subject': subject, 'body': h.rst_w_mentions(body)} kwargs.update(email_kwargs) email_body_html = EmailNotificationModel()\ .get_email_tmpl(type_, **kwargs) run_task(tasks.send_email, rec.email, email_subject, email_body, email_body_html) return notif
def index(self, repo_name): c.dbrepo = dbrepo = c.rhodecode_db_repo c.following = self.scm_model.is_following_repo( repo_name, self.rhodecode_user.user_id) def url_generator(**kw): return url('shortlog_home', repo_name=repo_name, size=10, **kw) c.repo_changesets = RepoPage(c.rhodecode_repo, page=1, items_per_page=10, url=url_generator) if self.rhodecode_user.username == 'default': # for default(anonymous) user we don't need to pass credentials username = '' password = '' else: username = str(self.rhodecode_user.username) password = '******' parsed_url = urlparse(url.current(qualified=True)) default_clone_uri = '{scheme}://{user}{pass}{netloc}{path}' uri_tmpl = config.get('clone_uri', default_clone_uri) uri_tmpl = uri_tmpl.replace('{', '%(').replace('}', ')s') decoded_path = safe_unicode(urllib.unquote(parsed_url.path)) uri_dict = { 'user': username, 'pass': password, 'scheme': parsed_url.scheme, 'netloc': parsed_url.netloc, 'path': decoded_path } uri = uri_tmpl % uri_dict # generate another clone url by id uri_dict.update({ 'path': decoded_path.replace(repo_name, '_%s' % c.dbrepo.repo_id) }) uri_id = uri_tmpl % uri_dict c.clone_repo_url = uri c.clone_repo_url_id = uri_id c.repo_tags = OrderedDict() for name, hash_ in c.rhodecode_repo.tags.items()[:10]: try: c.repo_tags[name] = c.rhodecode_repo.get_changeset(hash_) except ChangesetError: c.repo_tags[name] = EmptyChangeset(hash_) c.repo_branches = OrderedDict() for name, hash_ in c.rhodecode_repo.branches.items()[:10]: try: c.repo_branches[name] = c.rhodecode_repo.get_changeset(hash_) except ChangesetError: c.repo_branches[name] = EmptyChangeset(hash_) td = date.today() + timedelta(days=1) td_1m = td - timedelta(days=calendar.mdays[td.month]) td_1y = td - timedelta(days=365) ts_min_m = mktime(td_1m.timetuple()) ts_min_y = mktime(td_1y.timetuple()) ts_max_y = mktime(td.timetuple()) if dbrepo.enable_statistics: c.show_stats = True c.no_data_msg = _('No data loaded yet') run_task(get_commits_stats, c.dbrepo.repo_name, ts_min_y, ts_max_y) else: c.show_stats = False c.no_data_msg = _('Statistics are disabled for this repository') c.ts_min = ts_min_m c.ts_max = ts_max_y stats = self.sa.query(Statistics)\ .filter(Statistics.repository == dbrepo)\ .scalar() c.stats_percentage = 0 if stats and stats.languages: c.no_data = False is dbrepo.enable_statistics lang_stats_d = json.loads(stats.languages) c.commit_data = stats.commit_activity c.overview_data = stats.commit_activity_combined lang_stats = ((x, { "count": y, "desc": LANGUAGES_EXTENSIONS_MAP.get(x) }) for x, y in lang_stats_d.items()) c.trending_languages = json.dumps( sorted(lang_stats, reverse=True, key=lambda k: k[1])[:10]) last_rev = stats.stat_on_revision + 1 c.repo_last_rev = c.rhodecode_repo.count()\ if c.rhodecode_repo.revisions else 0 if last_rev == 0 or c.repo_last_rev == 0: pass else: c.stats_percentage = '%.2f' % ((float( (last_rev)) / c.repo_last_rev) * 100) else: c.commit_data = json.dumps({}) c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10]]) c.trending_languages = json.dumps({}) c.no_data = True c.enable_downloads = dbrepo.enable_downloads if c.enable_downloads: c.download_options = self._get_download_links(c.rhodecode_repo) c.readme_data, c.readme_file = self.__get_readme_data( c.rhodecode_db_repo.repo_name, c.rhodecode_repo) return render('summary/summary.html')
def reset_password(self, data): from rhodecode.lib.celerylib import tasks, run_task run_task(tasks.reset_user_password, data['email'])
def update(self, setting_id): """PUT /admin/settings/setting_id: Update an existing item""" # Forms posted to this method should contain a hidden field: # <input type="hidden" name="_method" value="PUT" /> # Or using helpers: # h.form(url('admin_setting', setting_id=ID), # method='put') # url('admin_setting', setting_id=ID) if setting_id == 'mapping': rm_obsolete = request.POST.get('destroy', False) log.debug('Rescanning directories with destroy=%s' % rm_obsolete) initial = ScmModel().repo_scan() log.debug('invalidating all repositories') for repo_name in initial.keys(): invalidate_cache('get_repo_cached_%s' % repo_name) added, removed = repo2db_mapper(initial, rm_obsolete) h.flash(_('Repositories successfully' ' rescanned added: %s,removed: %s') % (added, removed), category='success') if setting_id == 'whoosh': repo_location = self.get_hg_ui_settings()['paths_root_path'] full_index = request.POST.get('full_index', False) run_task(tasks.whoosh_index, repo_location, full_index) h.flash(_('Whoosh reindex task scheduled'), category='success') if setting_id == 'global': application_form = ApplicationSettingsForm()() try: form_result = application_form.to_python(dict(request.POST)) try: hgsettings1 = RhodeCodeSetting.get_by_name('title') hgsettings1.app_settings_value = \ form_result['rhodecode_title'] hgsettings2 = RhodeCodeSetting.get_by_name('realm') hgsettings2.app_settings_value = \ form_result['rhodecode_realm'] hgsettings3 = RhodeCodeSetting.get_by_name('ga_code') hgsettings3.app_settings_value = \ form_result['rhodecode_ga_code'] self.sa.add(hgsettings1) self.sa.add(hgsettings2) self.sa.add(hgsettings3) self.sa.commit() set_rhodecode_config(config) h.flash(_('Updated application settings'), category='success') except Exception: log.error(traceback.format_exc()) h.flash(_('error occurred during updating ' 'application settings'), category='error') self.sa.rollback() except formencode.Invalid, errors: return htmlfill.render( render('admin/settings/settings.html'), defaults=errors.value, errors=errors.error_dict or {}, prefix_error=False, encoding="UTF-8")
def get_commits_stats(repo_name, ts_min_y, ts_max_y, recurse_limit=100): log = get_logger(get_commits_stats) DBS = get_session() lockkey = __get_lockkey('get_commits_stats', repo_name, ts_min_y, ts_max_y) lockkey_path = config['app_conf']['cache_dir'] log.info('running task with lockkey %s' % lockkey) try: lock = l = DaemonLock(file_=jn(lockkey_path, lockkey)) # for js data compatibility cleans the key for person from ' akc = lambda k: person(k).replace('"', "") co_day_auth_aggr = {} commits_by_day_aggregate = {} repo = Repository.get_by_repo_name(repo_name) if repo is None: return True repo = repo.scm_instance repo_size = repo.count() # return if repo have no revisions if repo_size < 1: lock.release() return True skip_date_limit = True parse_limit = int(config['app_conf'].get('commit_parse_limit')) last_rev = None last_cs = None timegetter = itemgetter('time') dbrepo = DBS.query(Repository)\ .filter(Repository.repo_name == repo_name).scalar() cur_stats = DBS.query(Statistics)\ .filter(Statistics.repository == dbrepo).scalar() if cur_stats is not None: last_rev = cur_stats.stat_on_revision 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 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) log.debug('starting parsing %s' % parse_limit) lmktime = mktime last_rev = last_rev + 1 if last_rev >= 0 else 0 log.debug('Getting revisions from %s to %s' % (last_rev, last_rev + parse_limit)) for cs in repo[last_rev:last_rev + parse_limit]: log.debug('parsing %s' % cs) 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 ]) 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 = None if time_pos >= 0 and time_pos is not None: datadict = \ co_day_auth_aggr[akc(cs.author)]['data'][time_pos] 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: 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) else: if k >= ts_min_y and k <= ts_max_y or skip_date_limit: 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"], } #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 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"], } 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) log.debug('last revison %s' % last_rev) leftovers = len(repo.revisions[last_rev:]) log.debug('revisions to parse %s' % leftovers) if last_rev == 0 or leftovers < parse_limit: log.debug('getting code trending stats') stats.languages = json.dumps(__get_codes_stats(repo_name)) try: stats.repository = dbrepo stats.stat_on_revision = last_cs.revision if last_cs else 0 DBS.add(stats) DBS.commit() except: log.error(traceback.format_exc()) DBS.rollback() lock.release() return False # final release lock.release() # execute another task if celery is enabled if len(repo.revisions) > 1 and CELERY_ON and recurse_limit > 0: recurse_limit -= 1 run_task(get_commits_stats, repo_name, ts_min_y, ts_max_y, recurse_limit) if recurse_limit <= 0: log.debug('Breaking recursive mode due to reach of recurse limit') return True except LockHeld: log.info('LockHeld') return 'Task with key %s already running' % lockkey
def index(self, repo_name): e = request.environ c.dbrepo = dbrepo = c.rhodecode_db_repo c.following = self.scm_model.is_following_repo(repo_name, self.rhodecode_user.user_id) def url_generator(**kw): return url('shortlog_home', repo_name=repo_name, size=10, **kw) c.repo_changesets = RepoPage(c.rhodecode_repo, page=1, items_per_page=10, url=url_generator) if self.rhodecode_user.username == 'default': #for default(anonymous) user we don't need to pass credentials username = '' password = '' else: username = str(self.rhodecode_user.username) password = '******' if e.get('wsgi.url_scheme') == 'https': split_s = 'https://' else: split_s = 'http://' qualified_uri = [split_s] + [url.current(qualified=True)\ .split(split_s)[-1]] uri = u'%(proto)s%(user)s%(pass)s%(rest)s' \ % {'user': username, 'pass': password, 'proto': qualified_uri[0], 'rest': qualified_uri[1]} c.clone_repo_url = uri c.repo_tags = OrderedDict() for name, hash in c.rhodecode_repo.tags.items()[:10]: try: c.repo_tags[name] = c.rhodecode_repo.get_changeset(hash) except ChangesetError: c.repo_tags[name] = EmptyChangeset(hash) c.repo_branches = OrderedDict() for name, hash in c.rhodecode_repo.branches.items()[:10]: try: c.repo_branches[name] = c.rhodecode_repo.get_changeset(hash) except ChangesetError: c.repo_branches[name] = EmptyChangeset(hash) td = date.today() + timedelta(days=1) td_1m = td - timedelta(days=calendar.mdays[td.month]) td_1y = td - timedelta(days=365) ts_min_m = mktime(td_1m.timetuple()) ts_min_y = mktime(td_1y.timetuple()) ts_max_y = mktime(td.timetuple()) if dbrepo.enable_statistics: c.no_data_msg = _('No data loaded yet') run_task(get_commits_stats, c.dbrepo.repo_name, ts_min_y, ts_max_y) else: c.no_data_msg = _('Statistics are disabled for this repository') c.ts_min = ts_min_m c.ts_max = ts_max_y stats = self.sa.query(Statistics)\ .filter(Statistics.repository == dbrepo)\ .scalar() c.stats_percentage = 0 if stats and stats.languages: c.no_data = False is dbrepo.enable_statistics lang_stats_d = json.loads(stats.languages) c.commit_data = stats.commit_activity c.overview_data = stats.commit_activity_combined lang_stats = [(x, {"count": y, "desc": LANGUAGES_EXTENSIONS_MAP.get(x)}) for x, y in lang_stats_d.items()] c.trending_languages = json.dumps(OrderedDict( sorted(lang_stats, reverse=True, key=lambda k: k[1])[:10] ) ) last_rev = stats.stat_on_revision c.repo_last_rev = c.rhodecode_repo.count() - 1 \ if c.rhodecode_repo.revisions else 0 if last_rev == 0 or c.repo_last_rev == 0: pass else: c.stats_percentage = '%.2f' % ((float((last_rev)) / c.repo_last_rev) * 100) else: c.commit_data = json.dumps({}) c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10]]) c.trending_languages = json.dumps({}) c.no_data = True c.enable_downloads = dbrepo.enable_downloads if c.enable_downloads: c.download_options = self._get_download_links(c.rhodecode_repo) return render('summary/summary.html')
category='error') return redirect(url('admin_edit_setting', setting_id='hooks')) if setting_id == 'email': test_email = request.POST.get('test_email') test_email_subj = 'RhodeCode TestEmail' test_email_body = 'RhodeCode Email test' test_email_html_body = EmailNotificationModel()\ .get_email_tmpl(EmailNotificationModel.TYPE_DEFAULT, body=test_email_body) recipients = [test_email] if [test_email] else None run_task(tasks.send_email, recipients, test_email_subj, test_email_body, test_email_html_body) h.flash(_('Email task created'), category='success') return redirect(url('admin_settings')) @HasPermissionAllDecorator('hg.admin') def delete(self, setting_id): """DELETE /admin/settings/setting_id: Delete an existing item""" # Forms posted to this method should contain a hidden field: # <input type="hidden" name="_method" value="DELETE" /> # Or using helpers: # h.form(url('admin_setting', setting_id=ID), # method='delete') # url('admin_setting', setting_id=ID) if setting_id == 'hooks': hook_id = request.POST.get('hook_id')
def get_commits_stats(repo_name, ts_min_y, ts_max_y): log = get_logger(get_commits_stats) DBS = get_session() lockkey = __get_lockkey('get_commits_stats', repo_name, ts_min_y, ts_max_y) lockkey_path = config['here'] log.info('running task with lockkey %s' % lockkey) try: lock = l = DaemonLock(file_=jn(lockkey_path, lockkey)) # for js data compatibility cleans the key for person from ' akc = lambda k: person(k).replace('"', "") co_day_auth_aggr = {} commits_by_day_aggregate = {} repo = Repository.get_by_repo_name(repo_name) if repo is None: return True repo = repo.scm_instance repo_size = repo.count() # return if repo have no revisions if repo_size < 1: lock.release() return True skip_date_limit = True parse_limit = int(config['app_conf'].get('commit_parse_limit')) last_rev = None last_cs = None timegetter = itemgetter('time') dbrepo = DBS.query(Repository)\ .filter(Repository.repo_name == repo_name).scalar() cur_stats = DBS.query(Statistics)\ .filter(Statistics.repository == dbrepo).scalar() if cur_stats is not None: last_rev = cur_stats.stat_on_revision 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 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) log.debug('starting parsing %s' % parse_limit) lmktime = mktime last_rev = last_rev + 1 if last_rev >= 0 else 0 log.debug('Getting revisions from %s to %s' % ( last_rev, last_rev + parse_limit) ) for cs in repo[last_rev:last_rev + parse_limit]: log.debug('parsing %s' % cs) 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]) 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] 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: 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) else: if k >= ts_min_y and k <= ts_max_y or skip_date_limit: 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"], } #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 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"], } 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) log.debug('last revison %s' % last_rev) leftovers = len(repo.revisions[last_rev:]) log.debug('revisions to parse %s' % leftovers) if last_rev == 0 or leftovers < parse_limit: log.debug('getting code trending stats') stats.languages = json.dumps(__get_codes_stats(repo_name)) try: stats.repository = dbrepo stats.stat_on_revision = last_cs.revision if last_cs else 0 DBS.add(stats) DBS.commit() except: log.error(traceback.format_exc()) DBS.rollback() lock.release() return False # final release lock.release() # 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
def reset_password_link(self, data): from rhodecode.lib.celerylib import tasks, run_task run_task(tasks.send_password_link, data['email'])
def index(self, repo_name): c.dbrepo = dbrepo = c.rhodecode_db_repo c.following = self.scm_model.is_following_repo(repo_name, self.rhodecode_user.user_id) def url_generator(**kw): return url('shortlog_home', repo_name=repo_name, size=10, **kw) c.repo_changesets = RepoPage(c.rhodecode_repo, page=1, items_per_page=10, url=url_generator) if self.rhodecode_user.username == 'default': # for default(anonymous) user we don't need to pass credentials username = '' password = '' else: username = str(self.rhodecode_user.username) password = '******' parsed_url = urlparse(url.current(qualified=True)) default_clone_uri = '{scheme}://{user}{pass}{netloc}{path}' uri_tmpl = config.get('clone_uri', default_clone_uri) uri_tmpl = uri_tmpl.replace('{', '%(').replace('}', ')s') decoded_path = safe_unicode(urllib.unquote(parsed_url.path)) uri_dict = { 'user': username, 'pass': password, 'scheme': parsed_url.scheme, 'netloc': parsed_url.netloc, 'path': decoded_path } uri = uri_tmpl % uri_dict # generate another clone url by id uri_dict.update( {'path': decoded_path.replace(repo_name, '_%s' % c.dbrepo.repo_id)} ) uri_id = uri_tmpl % uri_dict c.clone_repo_url = uri c.clone_repo_url_id = uri_id c.repo_tags = OrderedDict() for name, hash_ in c.rhodecode_repo.tags.items()[:10]: try: c.repo_tags[name] = c.rhodecode_repo.get_changeset(hash_) except ChangesetError: c.repo_tags[name] = EmptyChangeset(hash_) c.repo_branches = OrderedDict() for name, hash_ in c.rhodecode_repo.branches.items()[:10]: try: c.repo_branches[name] = c.rhodecode_repo.get_changeset(hash_) except ChangesetError: c.repo_branches[name] = EmptyChangeset(hash_) td = date.today() + timedelta(days=1) td_1m = td - timedelta(days=calendar.mdays[td.month]) td_1y = td - timedelta(days=365) ts_min_m = mktime(td_1m.timetuple()) ts_min_y = mktime(td_1y.timetuple()) ts_max_y = mktime(td.timetuple()) if dbrepo.enable_statistics: c.show_stats = True c.no_data_msg = _('No data loaded yet') run_task(get_commits_stats, c.dbrepo.repo_name, ts_min_y, ts_max_y) else: c.show_stats = False c.no_data_msg = _('Statistics are disabled for this repository') c.ts_min = ts_min_m c.ts_max = ts_max_y stats = self.sa.query(Statistics)\ .filter(Statistics.repository == dbrepo)\ .scalar() c.stats_percentage = 0 if stats and stats.languages: c.no_data = False is dbrepo.enable_statistics lang_stats_d = json.loads(stats.languages) c.commit_data = stats.commit_activity c.overview_data = stats.commit_activity_combined lang_stats = ((x, {"count": y, "desc": LANGUAGES_EXTENSIONS_MAP.get(x)}) for x, y in lang_stats_d.items()) c.trending_languages = json.dumps( sorted(lang_stats, reverse=True, key=lambda k: k[1])[:10] ) last_rev = stats.stat_on_revision + 1 c.repo_last_rev = c.rhodecode_repo.count()\ if c.rhodecode_repo.revisions else 0 if last_rev == 0 or c.repo_last_rev == 0: pass else: c.stats_percentage = '%.2f' % ((float((last_rev)) / c.repo_last_rev) * 100) else: c.commit_data = json.dumps({}) c.overview_data = json.dumps([[ts_min_y, 0], [ts_max_y, 10]]) c.trending_languages = json.dumps({}) c.no_data = True c.enable_downloads = dbrepo.enable_downloads if c.enable_downloads: c.download_options = self._get_download_links(c.rhodecode_repo) c.readme_data, c.readme_file = self.__get_readme_data( c.rhodecode_db_repo.repo_name, c.rhodecode_repo ) return render('summary/summary.html')
def create(self, created_by, subject, body, recipients=None, type_=Notification.TYPE_MESSAGE, with_email=True, email_kwargs={}, email_subject=None): """ Creates notification of given type :param created_by: int, str or User instance. User who created this notification :param subject: :param body: :param recipients: list of int, str or User objects, when None is given send to all admins :param type_: type of notification :param with_email: send email with this notification :param email_kwargs: additional dict to pass as args to email template :param email_subject: use given subject as email subject """ from rhodecode.lib.celerylib import tasks, run_task if recipients and not getattr(recipients, '__iter__', False): raise Exception('recipients must be a list or iterable') created_by_obj = self._get_user(created_by) if recipients: recipients_objs = [] for u in recipients: obj = self._get_user(u) if obj: recipients_objs.append(obj) else: # TODO: inform user that requested operation couldn't be completed log.error('cannot email unknown user %r', u) recipients_objs = set(recipients_objs) log.debug('sending notifications %s to %s' % ( type_, recipients_objs) ) else: # empty recipients means to all admins recipients_objs = User.query().filter(User.admin == True).all() log.debug('sending notifications %s to admins: %s' % ( type_, recipients_objs) ) # TODO: inform user who are notified notif = Notification.create( created_by=created_by_obj, subject=subject, body=body, recipients=recipients_objs, type_=type_ ) if not with_email: return notif #don't send email to person who created this comment rec_objs = set(recipients_objs).difference(set([created_by_obj])) # send email with notification to all other participants for rec in rec_objs: if not email_subject: email_subject = NotificationModel()\ .make_description(notif, show_age=False) type_ = type_ email_body = None # we set body to none, we just send HTML emails ## this is passed into template kwargs = {'subject': subject, 'body': h.rst_w_mentions(body)} kwargs.update(email_kwargs) email_body_html = EmailNotificationModel()\ .get_email_tmpl(type_, **kwargs) run_task(tasks.send_email, rec.email, email_subject, email_body, email_body_html) return notif