Changeset - 31e6eb2fb4b2
[Not reviewed]
beta
0 4 1
Marcin Kuzminski - 14 years ago 2011-11-26 20:13:33
marcin@python-works.com
implements #222 registration feedback
- a notification message is created for admins
- email template with registartion
5 files changed with 60 insertions and 18 deletions:
0 comments (0 inline, 0 general)
rhodecode/controllers/login.py
Show inline comments
 
@@ -29,24 +29,25 @@ import formencode
 
from formencode import htmlfill
 

	
 
from pylons.i18n.translation import _
 
from pylons.controllers.util import abort, redirect
 
from pylons import request, response, session, tmpl_context as c, url
 

	
 
import rhodecode.lib.helpers as h
 
from rhodecode.lib.auth import AuthUser, HasPermissionAnyDecorator
 
from rhodecode.lib.base import BaseController, render
 
from rhodecode.model.db import User
 
from rhodecode.model.forms import LoginForm, RegisterForm, PasswordResetForm
 
from rhodecode.model.user import UserModel
 
from rhodecode.model.meta import Session
 

	
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
class LoginController(BaseController):
 

	
 
    def __before__(self):
 
        super(LoginController, self).__before__()
 

	
 
    def index(self):
 
        # redirect if already logged in
 
@@ -100,24 +101,25 @@ class LoginController(BaseController):
 
                c.auto_active = True
 
                break
 

	
 
        if request.POST:
 

	
 
            register_form = RegisterForm()()
 
            try:
 
                form_result = register_form.to_python(dict(request.POST))
 
                form_result['active'] = c.auto_active
 
                user_model.create_registration(form_result)
 
                h.flash(_('You have successfully registered into rhodecode'),
 
                            category='success')
 
                Session().commit()
 
                return redirect(url('login_home'))
 

	
 
            except formencode.Invalid, errors:
 
                return htmlfill.render(
 
                    render('/register.html'),
 
                    defaults=errors.value,
 
                    errors=errors.error_dict or {},
 
                    prefix_error=False,
 
                    encoding="UTF-8")
 

	
 
        return render('/register.html')
 

	
rhodecode/model/db.py
Show inline comments
 
@@ -274,24 +274,28 @@ class User(Base, BaseModel):
 
    user_log = relationship('UserLog', cascade='all')
 
    user_perms = relationship('UserToPerm', primaryjoin="User.user_id==UserToPerm.user_id", cascade='all')
 

	
 
    repositories = relationship('Repository')
 
    user_followers = relationship('UserFollowing', primaryjoin='UserFollowing.follows_user_id==User.user_id', cascade='all')
 
    repo_to_perm = relationship('UserRepoToPerm', primaryjoin='UserRepoToPerm.user_id==User.user_id', cascade='all')
 

	
 
    group_member = relationship('UsersGroupMember', cascade='all')
 

	
 
    notifications = relationship('UserNotification',)
 

	
 
    @property
 
    def full_name(self):
 
        return '%s %s' % (self.name, self.lastname)
 

	
 
    @property
 
    def full_contact(self):
 
        return '%s %s <%s>' % (self.name, self.lastname, self.email)
 

	
 
    @property
 
    def short_contact(self):
 
        return '%s %s' % (self.name, self.lastname)
 

	
 
    @property
 
    def is_admin(self):
 
        return self.admin
 

	
 
    def __repr__(self):
 
@@ -1161,24 +1165,25 @@ class ChangesetComment(Base, BaseModel):
 
        return Session().query(User)\
 
                .filter(cls.revision == revision)\
 
                .join(ChangesetComment.author).all()
 

	
 

	
 
class Notification(Base, BaseModel):
 
    __tablename__ = 'notifications'
 
    __table_args__ = ({'extend_existing':True})
 

	
 
    TYPE_CHANGESET_COMMENT = u'cs_comment'
 
    TYPE_MESSAGE = u'message'
 
    TYPE_MENTION = u'mention'
 
    TYPE_REGISTRATION = u'registration'
 

	
 
    notification_id = Column('notification_id', Integer(), nullable=False, primary_key=True)
 
    subject = Column('subject', Unicode(512), nullable=True)
 
    body = Column('body', Unicode(50000), nullable=True)
 
    created_by = Column("created_by", Integer(), ForeignKey('users.user_id'), nullable=True)
 
    created_on = Column('created_on', DateTime(timezone=False), nullable=False, default=datetime.datetime.now)
 
    type_ = Column('type', Unicode(256))
 

	
 
    created_by_user = relationship('User')
 
    notifications_to_users = relationship('UserNotification', lazy='joined',
 
                                          cascade="all, delete, delete-orphan")
 

	
rhodecode/model/notification.py
Show inline comments
 
@@ -48,63 +48,75 @@ class NotificationModel(BaseModel):
 
            return self._get_instance(User, user)
 

	
 
    def __get_notification(self, notification):
 
        if isinstance(notification, Notification):
 
            return notification
 
        elif isinstance(notification, int):
 
            return Notification.get(notification)
 
        else:
 
            if notification:
 
                raise Exception('notification must be int or Instance'
 
                                ' of Notification got %s' % type(notification))
 

	
 
    def create(self, created_by, subject, body, recipients,
 
               type_=Notification.TYPE_MESSAGE):
 
    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
 
        :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 not getattr(recipients, '__iter__', False):
 
        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)
 
        else:
 
            # empty recipients means to all admins
 
            recipients_objs = User.query().filter(User.admin == True).all()
 

	
 
        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_ = EmailNotificationModel.TYPE_CHANGESET_COMMENT
 
            type_ = type_
 
            email_body = body
 
            kwargs = {'subject':subject, 'body':h.rst(body)}
 
            kwargs.update(email_kwargs)
 
            email_body_html = EmailNotificationModel()\
 
                            .get_email_tmpl(type_, **{'subject':subject,
 
                                                      'body':h.rst(body)})
 
                                .get_email_tmpl(type_, **kwargs)
 
            run_task(tasks.send_email, rec.email, email_subject, email_body,
 
                     email_body_html)
 

	
 
        return notif
 

	
 
    def delete(self, user, notification):
 
        # we don't want to remove actual notification just the assignment
 
        try:
 
            notification = self.__get_notification(notification)
 
            user = self.__get_user(user)
 
            if notification and user:
 
                obj = UserNotification.query()\
 
@@ -141,25 +153,27 @@ class NotificationModel(BaseModel):
 
        return UserNotification.query()\
 
            .filter(UserNotification.notification == notification)\
 
            .filter(UserNotification.user == user).scalar()
 

	
 
    def make_description(self, notification, show_age=True):
 
        """
 
        Creates a human readable description based on properties
 
        of notification object
 
        """
 

	
 
        _map = {notification.TYPE_CHANGESET_COMMENT:_('commented on commit'),
 
                notification.TYPE_MESSAGE:_('sent message'),
 
                notification.TYPE_MENTION:_('mentioned you')}
 
                notification.TYPE_MENTION:_('mentioned you'),
 
                notification.TYPE_REGISTRATION:_('registered in RhodeCode')}
 

	
 
        DATETIME_FORMAT = "%Y-%m-%d %H:%M:%S"
 

	
 
        tmpl = "%(user)s %(action)s %(when)s"
 
        if show_age:
 
            when = h.age(notification.created_on)
 
        else:
 
            DTF = lambda d: datetime.datetime.strftime(d, DATETIME_FORMAT)
 
            when = DTF(notification.created_on)
 
        data = dict(user=notification.created_by_user.username,
 
                    action=_map[notification.type_],
 
                    when=when)
 
        return tmpl % data
rhodecode/model/user.py
Show inline comments
 
@@ -17,41 +17,44 @@
 
#
 
# 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.
 
#
 
# You should have received a copy of the GNU General Public License
 
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
 

	
 
import logging
 
import traceback
 

	
 
from pylons import url
 
from pylons.i18n.translation import _
 

	
 
from rhodecode.lib import safe_unicode
 
from rhodecode.lib.caching_query import FromCache
 

	
 
from rhodecode.model import BaseModel
 
from rhodecode.model.db import User, UserRepoToPerm, Repository, Permission, \
 
    UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember
 
    UserToPerm, UsersGroupRepoToPerm, UsersGroupToPerm, UsersGroupMember, \
 
    Notification
 
from rhodecode.lib.exceptions import DefaultUserException, \
 
    UserOwnsReposException
 

	
 
from sqlalchemy.exc import DatabaseError
 
from rhodecode.lib import generate_api_key
 
from sqlalchemy.orm import joinedload
 

	
 
log = logging.getLogger(__name__)
 

	
 

	
 
PERM_WEIGHTS = {'repository.none': 0,
 
                'repository.read': 1,
 
                'repository.write': 3,
 
                'repository.admin': 3}
 

	
 

	
 
class UserModel(BaseModel):
 

	
 
    def get(self, user_id, cache=False):
 
        user = self.sa.query(User)
 
        if cache:
 
            user = user.options(FromCache("sql_cache_short",
 
@@ -202,44 +205,53 @@ class UserModel(BaseModel):
 
                self.sa.add(new_user)
 
                self.sa.commit()
 
                return new_user
 
            except (DatabaseError,):
 
                log.error(traceback.format_exc())
 
                self.sa.rollback()
 
                raise
 
        log.debug('this %s user exists skipping creation of ldap account',
 
                  username)
 
        return None
 

	
 
    def create_registration(self, form_data):
 
        from rhodecode.lib.celerylib import tasks, run_task
 
        from rhodecode.model.notification import NotificationModel
 

	
 
        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()
 
            self.sa.flush()
 

	
 
            # notification to admins
 
            subject = _('new user registration')
 
            body = ('New user registration\n'
 
                    'username: %s\n'
 
                    'email: %s\n')
 
            body = body % (form_data['username'], form_data['email'])
 
                    '---------------------\n'
 
                    '- Username: %s\n'
 
                    '- Full Name: %s\n'
 
                    '- Email: %s\n')
 
            body = body % (new_user.username, new_user.full_name,
 
                           new_user.email)
 
            edit_url = url('edit_user', id=new_user.user_id, qualified=True)
 
            kw = {'registered_user_url':edit_url}
 
            NotificationModel().create(created_by=new_user, subject=subject,
 
                                       body=body, recipients=None,
 
                                       type_=Notification.TYPE_REGISTRATION,
 
                                       email_kwargs=kw)
 

	
 
            run_task(tasks.send_email, None,
 
                     _('[RhodeCode] New User registration'),
 
                     body)
 
        except:
 
            log.error(traceback.format_exc())
 
            self.sa.rollback()
 
            raise
 

	
 
    def update(self, user_id, form_data):
 
        try:
 
            user = self.get(user_id, cache=False)
 
            if user.username == 'default':
 
                raise DefaultUserException(
 
                                _("You can't Edit this user since it's"
 
                                  " crucial for entire application"))
 

	
 
            for k, v in form_data.items():
 
                if k == 'new_password' and v != '':
rhodecode/templates/email_templates/registration.html
Show inline comments
 
new file 100644
 
## -*- coding: utf-8 -*-
 
<%inherit file="main.html"/>
 

	
 
A new user have registered in RhodeCode
 

	
 
${body}
 

	
 

	
 
View this user here :${registered_user_url}
 
\ No newline at end of file
0 comments (0 inline, 0 general)