Пример #1
0
    def make_description(self, notification, show_age=True):
        """
        Creates a human readable description based on properties
        of notification object
        """
        #alias
        _n = notification
        _map = {
            _n.TYPE_CHANGESET_COMMENT:
            _('%(user)s commented on changeset at %(when)s'),
            _n.TYPE_MESSAGE:
            _('%(user)s sent message at %(when)s'),
            _n.TYPE_MENTION:
            _('%(user)s mentioned you at %(when)s'),
            _n.TYPE_REGISTRATION:
            _('%(user)s registered in Kallithea at %(when)s'),
            _n.TYPE_PULL_REQUEST:
            _('%(user)s opened new pull request at %(when)s'),
            _n.TYPE_PULL_REQUEST_COMMENT:
            _('%(user)s commented on pull request at %(when)s')
        }
        tmpl = _map[notification.type_]

        if show_age:
            when = h.age(notification.created_on)
        else:
            when = h.fmt_date(notification.created_on)

        return tmpl % dict(
            user=notification.created_by_user.username,
            when=when,
        )
Пример #2
0
    def __get_desc(self, cs):
        desc_msg = [(_('%s committed on %s') %
                     (h.person(cs.author), h.fmt_date(cs.date))) + '<br/>']
        #branches, tags, bookmarks
        if cs.branch:
            desc_msg.append('branch: %s<br/>' % cs.branch)
        if h.is_hg(c.db_repo_scm_instance):
            for book in cs.bookmarks:
                desc_msg.append('bookmark: %s<br/>' % book)
        for tag in cs.tags:
            desc_msg.append('tag: %s<br/>' % tag)
        diff_processor, changes = self.__changes(cs)
        # rev link
        _url = h.canonical_url('changeset_home',
                               repo_name=c.db_repo.repo_name,
                               revision=cs.raw_id)
        desc_msg.append('changeset: <a href="%s">%s</a>' %
                        (_url, cs.raw_id[:8]))

        desc_msg.append('<pre>')
        desc_msg.append(h.urlify_text(cs.message))
        desc_msg.append('\n')
        desc_msg.extend(changes)
        if self.include_diff:
            desc_msg.append('\n\n')
            desc_msg.append(diff_processor.as_raw())
        desc_msg.append('</pre>')
        return map(safe_unicode, desc_msg)
Пример #3
0
    def __get_desc(self, cs):
        desc_msg = [(_('%s committed on %s')
                     % (h.person(cs.author), h.fmt_date(cs.date))) + '<br/>']
        #branches, tags, bookmarks
        if cs.branch:
            desc_msg.append('branch: %s<br/>' % cs.branch)
        if h.is_hg(c.db_repo_scm_instance):
            for book in cs.bookmarks:
                desc_msg.append('bookmark: %s<br/>' % book)
        for tag in cs.tags:
            desc_msg.append('tag: %s<br/>' % tag)
        diff_processor, changes = self.__changes(cs)
        # rev link
        _url = h.canonical_url('changeset_home', repo_name=c.db_repo.repo_name,
                   revision=cs.raw_id)
        desc_msg.append('changeset: <a href="%s">%s</a>' % (_url, cs.raw_id[:8]))

        desc_msg.append('<pre>')
        desc_msg.append(h.urlify_text(cs.message))
        desc_msg.append('\n')
        desc_msg.extend(changes)
        if self.include_diff:
            desc_msg.append('\n\n')
            desc_msg.append(diff_processor.as_raw())
        desc_msg.append('</pre>')
        return map(safe_unicode, desc_msg)
Пример #4
0
    def make_description(self, notification, show_age=True):
        """
        Creates a human readable description based on properties
        of notification object
        """
        #alias
        _n = notification

        if show_age:
            return {
                    _n.TYPE_CHANGESET_COMMENT: _('%(user)s commented on changeset %(age)s'),
                    _n.TYPE_MESSAGE: _('%(user)s sent message %(age)s'),
                    _n.TYPE_MENTION: _('%(user)s mentioned you %(age)s'),
                    _n.TYPE_REGISTRATION: _('%(user)s registered in Kallithea %(age)s'),
                    _n.TYPE_PULL_REQUEST: _('%(user)s opened new pull request %(age)s'),
                    _n.TYPE_PULL_REQUEST_COMMENT: _('%(user)s commented on pull request %(age)s'),
                }[notification.type_] % dict(
                    user=notification.created_by_user.username,
                    age=h.age(notification.created_on),
                )
        else:
            return {
                    _n.TYPE_CHANGESET_COMMENT: _('%(user)s commented on changeset at %(when)s'),
                    _n.TYPE_MESSAGE: _('%(user)s sent message at %(when)s'),
                    _n.TYPE_MENTION: _('%(user)s mentioned you at %(when)s'),
                    _n.TYPE_REGISTRATION: _('%(user)s registered in Kallithea at %(when)s'),
                    _n.TYPE_PULL_REQUEST: _('%(user)s opened new pull request at %(when)s'),
                    _n.TYPE_PULL_REQUEST_COMMENT: _('%(user)s commented on pull request at %(when)s'),
                }[notification.type_] % dict(
                    user=notification.created_by_user.username,
                    when=h.fmt_date(notification.created_on),
                )
Пример #5
0
    def index(self, format='html'):
        """GET /users: All items in the collection"""
        # url('users')

        c.users_list = User.query().order_by(User.username)\
                        .filter(User.username != User.DEFAULT_USER)\
                        .order_by(func.lower(User.username))\
                        .all()

        users_data = []
        total_records = len(c.users_list)
        _tmpl_lookup = kallithea.CONFIG['pylons.app_globals'].mako_lookup
        template = _tmpl_lookup.get_template('data_table/_dt_elements.html')

        grav_tmpl = '<div class="gravatar">%s</div>'

        username = lambda user_id, username: (template.get_def(
            "user_name").render(user_id, username, _=_, h=h, c=c))

        user_actions = lambda user_id, username: (template.get_def(
            "user_actions").render(user_id, username, _=_, h=h, c=c))

        for user in c.users_list:
            users_data.append({
                "gravatar":
                grav_tmpl % h.gravatar(user.email, size=20),
                "raw_name":
                user.username,
                "username":
                username(user.user_id, user.username),
                "firstname":
                user.name,
                "lastname":
                user.lastname,
                "last_login":
                h.fmt_date(user.last_login),
                "last_login_raw":
                datetime_to_time(user.last_login),
                "active":
                h.boolicon(user.active),
                "admin":
                h.boolicon(user.admin),
                "extern_type":
                user.extern_type,
                "extern_name":
                user.extern_name,
                "action":
                user_actions(user.user_id, user.username),
            })

        c.data = json.dumps({
            "totalRecords": total_records,
            "startIndex": 0,
            "sort": None,
            "dir": "asc",
            "records": users_data
        })

        return render('admin/users/users.html')
Пример #6
0
    def delete(self, repo_name, revision, f_path):
        repo = c.db_repo
        if repo.enable_locking and repo.locked[0]:
            h.flash(_('This repository has been locked by %s on %s')
                % (h.person_by_id(repo.locked[0]),
                   h.fmt_date(h.time_to_datetime(repo.locked[1]))),
                'warning')
            raise HTTPFound(location=h.url('files_home',
                                  repo_name=repo_name, revision='tip'))

        # check if revision is a branch identifier- basically we cannot
        # create multiple heads via file editing
        _branches = repo.scm_instance.branches
        # check if revision is a branch name or branch hash
        if revision not in _branches.keys() + _branches.values():
            h.flash(_('You can only delete files with revision '
                      'being a valid branch'), category='warning')
            raise HTTPFound(location=h.url('files_home',
                                  repo_name=repo_name, revision='tip',
                                  f_path=f_path))

        r_post = request.POST

        c.cs = self.__get_cs(revision)
        c.file = self.__get_filenode(c.cs, f_path)

        c.default_message = _('Deleted file %s via Kallithea') % (f_path)
        c.f_path = f_path
        node_path = f_path
        author = self.authuser.full_contact

        if r_post:
            message = r_post.get('message') or c.default_message

            try:
                nodes = {
                    node_path: {
                        'content': ''
                    }
                }
                self.scm_model.delete_nodes(
                    user=c.authuser.user_id, repo=c.db_repo,
                    message=message,
                    nodes=nodes,
                    parent_cs=c.cs,
                    author=author,
                )

                h.flash(_('Successfully deleted file %s') % f_path,
                        category='success')
            except Exception:
                log.error(traceback.format_exc())
                h.flash(_('Error occurred during commit'), category='error')
            raise HTTPFound(location=url('changeset_home',
                                repo_name=c.repo_name, revision='tip'))

        return render('files/files_delete.html')
Пример #7
0
    def delete(self, repo_name, revision, f_path):
        repo = c.db_repo
        if repo.enable_locking and repo.locked[0]:
            h.flash(_('This repository has been locked by %s on %s')
                % (h.person_by_id(repo.locked[0]),
                   h.fmt_date(h.time_to_datetime(repo.locked[1]))),
                'warning')
            raise HTTPFound(location=h.url('files_home',
                                  repo_name=repo_name, revision='tip'))

        # check if revision is a branch identifier- basically we cannot
        # create multiple heads via file editing
        _branches = repo.scm_instance.branches
        # check if revision is a branch name or branch hash
        if revision not in _branches.keys() + _branches.values():
            h.flash(_('You can only delete files with revision '
                      'being a valid branch'), category='warning')
            raise HTTPFound(location=h.url('files_home',
                                  repo_name=repo_name, revision='tip',
                                  f_path=f_path))

        r_post = request.POST

        c.cs = self.__get_cs(revision)
        c.file = self.__get_filenode(c.cs, f_path)

        c.default_message = _('Deleted file %s via Kallithea') % (f_path)
        c.f_path = f_path
        node_path = f_path
        author = request.authuser.full_contact

        if r_post:
            message = r_post.get('message') or c.default_message

            try:
                nodes = {
                    node_path: {
                        'content': ''
                    }
                }
                self.scm_model.delete_nodes(
                    user=request.authuser.user_id, repo=c.db_repo,
                    message=message,
                    nodes=nodes,
                    parent_cs=c.cs,
                    author=author,
                )

                h.flash(_('Successfully deleted file %s') % f_path,
                        category='success')
            except Exception:
                log.error(traceback.format_exc())
                h.flash(_('Error occurred during commit'), category='error')
            raise HTTPFound(location=url('changeset_home',
                                repo_name=c.repo_name, revision='tip'))

        return render('files/files_delete.html')
    def test_description_with_datetime(self):
        self.log_user()
        with test_context(self.app):
            cur_user = self._get_logged_user()
            subject = u'test'
            notify_body = u'hi there'
            notification = NotificationModel().create(created_by=cur_user,
                                                      subject=subject,
                                                      body=notify_body)

            description = NotificationModel().make_description(
                notification, False)
            assert description == "{0} sent message at {1}".format(
                cur_user.username, h.fmt_date(notification.created_on))
Пример #9
0
    def index(self, format='html'):
        """GET /users: All items in the collection"""
        # url('users')

        c.users_list = User.query().order_by(User.username) \
                        .filter(User.username != User.DEFAULT_USER) \
                        .order_by(func.lower(User.username)) \
                        .all()

        users_data = []
        total_records = len(c.users_list)
        _tmpl_lookup = kallithea.CONFIG['pylons.app_globals'].mako_lookup
        template = _tmpl_lookup.get_template('data_table/_dt_elements.html')

        grav_tmpl = '<div class="gravatar">%s</div>'

        username = lambda user_id, username: (
                template.get_def("user_name")
                .render(user_id, username, _=_, h=h, c=c))

        user_actions = lambda user_id, username: (
                template.get_def("user_actions")
                .render(user_id, username, _=_, h=h, c=c))

        for user in c.users_list:
            users_data.append({
                "gravatar": grav_tmpl % h.gravatar(user.email, size=20),
                "raw_name": user.username,
                "username": username(user.user_id, user.username),
                "firstname": h.escape(user.name),
                "lastname": h.escape(user.lastname),
                "last_login": h.fmt_date(user.last_login),
                "last_login_raw": datetime_to_time(user.last_login),
                "active": h.boolicon(user.active),
                "admin": h.boolicon(user.admin),
                "extern_type": user.extern_type,
                "extern_name": user.extern_name,
                "action": user_actions(user.user_id, user.username),
            })

        c.data = json.dumps({
            "totalRecords": total_records,
            "startIndex": 0,
            "sort": None,
            "dir": "asc",
            "records": users_data
        })

        return render('admin/users/users.html')
    def test_description_with_datetime(self):
        self.log_user()
        with test_context(self.app):
            cur_user = self._get_logged_user()
            subject = u'test'
            notify_body = u'hi there'
            notification = NotificationModel().create(created_by = cur_user,
                                                      subject    = subject,
                                                      body       = notify_body)

            description = NotificationModel().make_description(notification, False)
            assert description == "{0} sent message at {1}".format(
                    cur_user.username,
                    h.fmt_date(notification.created_on)
                    )
Пример #11
0
    def index(self, format='html'):
        c.users_list = User.query().order_by(User.username) \
                        .filter_by(is_default_user=False) \
                        .order_by(func.lower(User.username)) \
                        .all()

        users_data = []
        total_records = len(c.users_list)
        _tmpl_lookup = app_globals.mako_lookup
        template = _tmpl_lookup.get_template('data_table/_dt_elements.html')

        grav_tmpl = '<div class="gravatar">%s</div>'

        username = lambda user_id, username: (
                template.get_def("user_name")
                .render(user_id, username, _=_, h=h, c=c))

        user_actions = lambda user_id, username: (
                template.get_def("user_actions")
                .render(user_id, username, _=_, h=h, c=c))

        for user in c.users_list:
            users_data.append({
                "gravatar": grav_tmpl % h.gravatar(user.email, size=20),
                "raw_name": user.username,
                "username": username(user.user_id, user.username),
                "firstname": h.escape(user.name),
                "lastname": h.escape(user.lastname),
                "last_login": h.fmt_date(user.last_login),
                "last_login_raw": datetime_to_time(user.last_login),
                "active": h.boolicon(user.active),
                "admin": h.boolicon(user.admin),
                "extern_type": user.extern_type,
                "extern_name": user.extern_name,
                "action": user_actions(user.user_id, user.username),
            })

        c.data = {
            "totalRecords": total_records,
            "startIndex": 0,
            "sort": None,
            "dir": "asc",
            "records": users_data
        }

        return render('admin/users/users.html')
Пример #12
0
    def add(self, repo_name, revision, f_path):

        repo = c.db_repo
        if repo.enable_locking and repo.locked[0]:
            h.flash(_('This repository has been locked by %s on %s')
                % (h.person_by_id(repo.locked[0]),
                   h.fmt_date(h.time_to_datetime(repo.locked[1]))),
                  'warning')
            raise HTTPFound(location=h.url('files_home',
                                  repo_name=repo_name, revision='tip'))

        r_post = request.POST
        c.cs = self.__get_cs(revision, silent_empty=True)
        if c.cs is None:
            c.cs = EmptyChangeset(alias=c.db_repo_scm_instance.alias)
        c.default_message = (_('Added file via Kallithea'))
        c.f_path = f_path

        if r_post:
            unix_mode = 0
            content = convert_line_endings(r_post.get('content', ''), unix_mode)

            message = r_post.get('message') or c.default_message
            filename = r_post.get('filename')
            location = r_post.get('location', '')
            file_obj = r_post.get('upload_file', None)

            if file_obj is not None and hasattr(file_obj, 'filename'):
                filename = file_obj.filename
                content = file_obj.file

                if hasattr(content, 'file'):
                    # non posix systems store real file under file attr
                    content = content.file

            if not content:
                h.flash(_('No content'), category='warning')
                raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name,
                                    revision='tip'))
            if not filename:
                h.flash(_('No filename'), category='warning')
                raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name,
                                    revision='tip'))
            #strip all crap out of file, just leave the basename
            filename = os.path.basename(filename)
            node_path = posixpath.join(location, filename)
            author = request.authuser.full_contact

            try:
                nodes = {
                    node_path: {
                        'content': content
                    }
                }
                self.scm_model.create_nodes(
                    user=request.authuser.user_id, repo=c.db_repo,
                    message=message,
                    nodes=nodes,
                    parent_cs=c.cs,
                    author=author,
                )

                h.flash(_('Successfully committed to %s') % node_path,
                        category='success')
            except NonRelativePathError as e:
                h.flash(_('Location must be relative path and must not '
                          'contain .. in path'), category='warning')
                raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name,
                                    revision='tip'))
            except (NodeError, NodeAlreadyExistsError) as e:
                h.flash(_(e), category='error')
            except Exception:
                log.error(traceback.format_exc())
                h.flash(_('Error occurred during commit'), category='error')
            raise HTTPFound(location=url('changeset_home',
                                repo_name=c.repo_name, revision='tip'))

        return render('files/files_add.html')
Пример #13
0
    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 kallithea.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)

        recipients_objs = []
        if recipients:
            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))
        elif recipients is None:
            # 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))
        #else: silently skip notification mails?

        # 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]))

        headers = None
        if 'threading' in email_kwargs:
            headers = {
                'References':
                ' '.join('<%s>' % x for x in email_kwargs['threading'])
            }

        # send email with notification to all other participants
        for rec in rec_objs:
            ## this is passed into template
            html_kwargs = {
                'subject': subject,
                'body': h.rst_w_mentions(body),
                'when': h.fmt_date(notif.created_on),
                'user': notif.created_by_user.username,
            }

            txt_kwargs = {
                'subject': subject,
                'body': body,
                'when': h.fmt_date(notif.created_on),
                'user': notif.created_by_user.username,
            }

            html_kwargs.update(email_kwargs)
            txt_kwargs.update(email_kwargs)
            email_subject = EmailNotificationModel()\
                                .get_email_description(type_, **txt_kwargs)
            email_txt_body = EmailNotificationModel()\
                                .get_email_tmpl(type_, 'txt', **txt_kwargs)
            email_html_body = EmailNotificationModel()\
                                .get_email_tmpl(type_, 'html', **html_kwargs)

            run_task(tasks.send_email, [rec.email], email_subject,
                     email_txt_body, email_html_body, headers)

        return notif
Пример #14
0
    def edit(self, repo_name, revision, f_path):
        repo = c.db_repo
        if repo.enable_locking and repo.locked[0]:
            h.flash(_('This repository has been locked by %s on %s')
                % (h.person_by_id(repo.locked[0]),
                   h.fmt_date(h.time_to_datetime(repo.locked[1]))),
                'warning')
            raise HTTPFound(location=h.url('files_home',
                                  repo_name=repo_name, revision='tip'))

        # check if revision is a branch identifier- basically we cannot
        # create multiple heads via file editing
        _branches = repo.scm_instance.branches
        # check if revision is a branch name or branch hash
        if revision not in _branches.keys() + _branches.values():
            h.flash(_('You can only edit files with revision '
                      'being a valid branch'), category='warning')
            raise HTTPFound(location=h.url('files_home',
                                  repo_name=repo_name, revision='tip',
                                  f_path=f_path))

        r_post = request.POST

        c.cs = self.__get_cs(revision)
        c.file = self.__get_filenode(c.cs, f_path)

        if c.file.is_binary:
            raise HTTPFound(location=url('files_home', repo_name=c.repo_name,
                            revision=c.cs.raw_id, f_path=f_path))
        c.default_message = _('Edited file %s via Kallithea') % (f_path)
        c.f_path = f_path

        if r_post:

            old_content = c.file.content
            sl = old_content.splitlines(1)
            first_line = sl[0] if sl else ''
            # modes:  0 - Unix, 1 - Mac, 2 - DOS
            mode = detect_mode(first_line, 0)
            content = convert_line_endings(r_post.get('content', ''), mode)

            message = r_post.get('message') or c.default_message
            author = self.authuser.full_contact

            if content == old_content:
                h.flash(_('No changes'), category='warning')
                raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name,
                                    revision='tip'))
            try:
                self.scm_model.commit_change(repo=c.db_repo_scm_instance,
                                             repo_name=repo_name, cs=c.cs,
                                             user=self.authuser.user_id,
                                             author=author, message=message,
                                             content=content, f_path=f_path)
                h.flash(_('Successfully committed to %s') % f_path,
                        category='success')
            except Exception:
                log.error(traceback.format_exc())
                h.flash(_('Error occurred during commit'), category='error')
            raise HTTPFound(location=url('changeset_home',
                                repo_name=c.repo_name, revision='tip'))

        return render('files/files_edit.html')
Пример #15
0
    def create(self,
               created_by,
               subject,
               body,
               recipients=None,
               type_=TYPE_MESSAGE,
               with_email=True,
               email_kwargs=None,
               repo_name=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
        """
        from kallithea.lib.celerylib import tasks
        email_kwargs = email_kwargs or {}
        if recipients and not getattr(recipients, '__iter__', False):
            raise Exception('recipients must be a list or iterable')

        created_by_obj = User.guess_instance(created_by)

        recipients_objs = set()
        if recipients:
            for u in recipients:
                obj = User.guess_instance(u)
                if obj is not None:
                    recipients_objs.add(obj)
                else:
                    # TODO: inform user that requested operation couldn't be completed
                    log.error('cannot email unknown user %r', u)
            log.debug('sending notifications %s to %s', type_, recipients_objs)
        elif recipients is None:
            # 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)
        #else: silently skip notification mails?

        if not with_email:
            return

        headers = {}
        headers['X-Kallithea-Notification-Type'] = type_
        if 'threading' in email_kwargs:
            headers['References'] = ' '.join(
                '<%s>' % x for x in email_kwargs['threading'])

        # this is passed into template
        created_on = h.fmt_date(datetime.datetime.now())
        html_kwargs = {
            'subject': subject,
            'body': h.render_w_mentions(body, repo_name),
            'when': created_on,
            'user': created_by_obj.username,
        }

        txt_kwargs = {
            'subject': subject,
            'body': body,
            'when': created_on,
            'user': created_by_obj.username,
        }

        html_kwargs.update(email_kwargs)
        txt_kwargs.update(email_kwargs)
        email_subject = EmailNotificationModel() \
                            .get_email_description(type_, **txt_kwargs)
        email_txt_body = EmailNotificationModel() \
                            .get_email_tmpl(type_, 'txt', **txt_kwargs)
        email_html_body = EmailNotificationModel() \
                            .get_email_tmpl(type_, 'html', **html_kwargs)

        # 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:
            tasks.send_email([rec.email],
                             email_subject,
                             email_txt_body,
                             email_html_body,
                             headers,
                             from_name=created_by_obj.full_name_or_username)
Пример #16
0
    def create(self, created_by, subject, body, recipients=None,
               type_=Notification.TYPE_MESSAGE, with_email=True,
               email_kwargs=None, repo_name=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
        """
        from kallithea.lib.celerylib import tasks, run_task
        email_kwargs = email_kwargs or {}
        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)

        recipients_objs = []
        if recipients:
            for u in recipients:
                obj = self._get_user(u)
                if obj is not None:
                    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
            )
        elif recipients is None:
            # 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
            )
        #else: silently skip notification mails?

        # 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]))

        headers = None
        if 'threading' in email_kwargs:
            headers = {'References': ' '.join('<%s>' % x for x in email_kwargs['threading'])}

        # send email with notification to all other participants
        for rec in rec_objs:
            ## this is passed into template
            html_kwargs = {
                      'subject': subject,
                      'body': h.render_w_mentions(body, repo_name),
                      'when': h.fmt_date(notif.created_on),
                      'user': notif.created_by_user.username,
                      }

            txt_kwargs = {
                      'subject': subject,
                      'body': body,
                      'when': h.fmt_date(notif.created_on),
                      'user': notif.created_by_user.username,
                      }

            html_kwargs.update(email_kwargs)
            txt_kwargs.update(email_kwargs)
            email_subject = EmailNotificationModel() \
                                .get_email_description(type_, **txt_kwargs)
            email_txt_body = EmailNotificationModel() \
                                .get_email_tmpl(type_, 'txt', **txt_kwargs)
            email_html_body = EmailNotificationModel() \
                                .get_email_tmpl(type_, 'html', **html_kwargs)

            run_task(tasks.send_email, [rec.email], email_subject, email_txt_body,
                     email_html_body, headers, author=created_by_obj)

        return notif
Пример #17
0
    def edit(self, repo_name, revision, f_path):
        repo = c.db_repo
        if repo.enable_locking and repo.locked[0]:
            h.flash(_('This repository has been locked by %s on %s')
                % (h.person_by_id(repo.locked[0]),
                   h.fmt_date(h.time_to_datetime(repo.locked[1]))),
                'warning')
            raise HTTPFound(location=h.url('files_home',
                                  repo_name=repo_name, revision='tip'))

        # check if revision is a branch identifier- basically we cannot
        # create multiple heads via file editing
        _branches = repo.scm_instance.branches
        # check if revision is a branch name or branch hash
        if revision not in _branches.keys() + _branches.values():
            h.flash(_('You can only edit files with revision '
                      'being a valid branch'), category='warning')
            raise HTTPFound(location=h.url('files_home',
                                  repo_name=repo_name, revision='tip',
                                  f_path=f_path))

        r_post = request.POST

        c.cs = self.__get_cs(revision)
        c.file = self.__get_filenode(c.cs, f_path)

        if c.file.is_binary:
            raise HTTPFound(location=url('files_home', repo_name=c.repo_name,
                            revision=c.cs.raw_id, f_path=f_path))
        c.default_message = _('Edited file %s via Kallithea') % (f_path)
        c.f_path = f_path

        if r_post:

            old_content = c.file.content
            sl = old_content.splitlines(1)
            first_line = sl[0] if sl else ''
            # modes:  0 - Unix, 1 - Mac, 2 - DOS
            mode = detect_mode(first_line, 0)
            content = convert_line_endings(r_post.get('content', ''), mode)

            message = r_post.get('message') or c.default_message
            author = request.authuser.full_contact

            if content == old_content:
                h.flash(_('No changes'), category='warning')
                raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name,
                                    revision='tip'))
            try:
                self.scm_model.commit_change(repo=c.db_repo_scm_instance,
                                             repo_name=repo_name, cs=c.cs,
                                             user=request.authuser.user_id,
                                             author=author, message=message,
                                             content=content, f_path=f_path)
                h.flash(_('Successfully committed to %s') % f_path,
                        category='success')
            except Exception:
                log.error(traceback.format_exc())
                h.flash(_('Error occurred during commit'), category='error')
            raise HTTPFound(location=url('changeset_home',
                                repo_name=c.repo_name, revision='tip'))

        return render('files/files_edit.html')
Пример #18
0
    def add(self, repo_name, revision, f_path):

        repo = Repository.get_by_repo_name(repo_name)
        if repo.enable_locking and repo.locked[0]:
            h.flash(_('This repository has been locked by %s on %s')
                % (h.person_by_id(repo.locked[0]),
                   h.fmt_date(h.time_to_datetime(repo.locked[1]))),
                  'warning')
            raise HTTPFound(location=h.url('files_home',
                                  repo_name=repo_name, revision='tip'))

        r_post = request.POST
        c.cs = self.__get_cs(revision, silent_empty=True)
        if c.cs is None:
            c.cs = EmptyChangeset(alias=c.db_repo_scm_instance.alias)
        c.default_message = (_('Added file via Kallithea'))
        c.f_path = f_path

        if r_post:
            unix_mode = 0
            content = convert_line_endings(r_post.get('content', ''), unix_mode)

            message = r_post.get('message') or c.default_message
            filename = r_post.get('filename')
            location = r_post.get('location', '')
            file_obj = r_post.get('upload_file', None)

            if file_obj is not None and hasattr(file_obj, 'filename'):
                filename = file_obj.filename
                content = file_obj.file

                if hasattr(content, 'file'):
                    # non posix systems store real file under file attr
                    content = content.file

            if not content:
                h.flash(_('No content'), category='warning')
                raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name,
                                    revision='tip'))
            if not filename:
                h.flash(_('No filename'), category='warning')
                raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name,
                                    revision='tip'))
            #strip all crap out of file, just leave the basename
            filename = os.path.basename(filename)
            node_path = posixpath.join(location, filename)
            author = self.authuser.full_contact

            try:
                nodes = {
                    node_path: {
                        'content': content
                    }
                }
                self.scm_model.create_nodes(
                    user=c.authuser.user_id, repo=c.db_repo,
                    message=message,
                    nodes=nodes,
                    parent_cs=c.cs,
                    author=author,
                )

                h.flash(_('Successfully committed to %s') % node_path,
                        category='success')
            except NonRelativePathError as e:
                h.flash(_('Location must be relative path and must not '
                          'contain .. in path'), category='warning')
                raise HTTPFound(location=url('changeset_home', repo_name=c.repo_name,
                                    revision='tip'))
            except (NodeError, NodeAlreadyExistsError) as e:
                h.flash(_(e), category='error')
            except Exception:
                log.error(traceback.format_exc())
                h.flash(_('Error occurred during commit'), category='error')
            raise HTTPFound(location=url('changeset_home',
                                repo_name=c.repo_name, revision='tip'))

        return render('files/files_add.html')