emails: updated emails design and data structure they provide.
- more consistent UI for emails - nicer formatting, plaintext emails - major cleanup and fixes lots of incosistencies - additionally debug-style now allows to test emails in browser for faster development
This commit is contained in:
parent
a5dd4ceb99
commit
453a6ee9a2
23 changed files with 1284 additions and 265 deletions
|
|
@ -42,6 +42,14 @@ def includeme(config):
|
|||
name='debug_style_home',
|
||||
pattern=ADMIN_PREFIX + '/debug_style',
|
||||
debug_style=True)
|
||||
config.add_route(
|
||||
name='debug_style_email',
|
||||
pattern=ADMIN_PREFIX + '/debug_style/email/{email_id}',
|
||||
debug_style=True)
|
||||
config.add_route(
|
||||
name='debug_style_email_plain_rendered',
|
||||
pattern=ADMIN_PREFIX + '/debug_style/email-rendered/{email_id}',
|
||||
debug_style=True)
|
||||
config.add_route(
|
||||
name='debug_style_template',
|
||||
pattern=ADMIN_PREFIX + '/debug_style/t/{t_path}',
|
||||
|
|
|
|||
|
|
@ -20,10 +20,15 @@
|
|||
|
||||
import os
|
||||
import logging
|
||||
import datetime
|
||||
|
||||
from pyramid.view import view_config
|
||||
from pyramid.renderers import render_to_response
|
||||
from rhodecode.apps._base import BaseAppView
|
||||
from rhodecode.lib.celerylib import run_task, tasks
|
||||
from rhodecode.lib.utils2 import AttributeDict
|
||||
from rhodecode.model.db import User
|
||||
from rhodecode.model.notification import EmailNotificationModel
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
|
@ -45,6 +50,271 @@ class DebugStyleView(BaseAppView):
|
|||
'debug_style/index.html', self._get_template_context(c),
|
||||
request=self.request)
|
||||
|
||||
@view_config(
|
||||
route_name='debug_style_email', request_method='GET',
|
||||
renderer=None)
|
||||
@view_config(
|
||||
route_name='debug_style_email_plain_rendered', request_method='GET',
|
||||
renderer=None)
|
||||
def render_email(self):
|
||||
c = self.load_default_context()
|
||||
email_id = self.request.matchdict['email_id']
|
||||
c.active = 'emails'
|
||||
|
||||
pr = AttributeDict(
|
||||
pull_request_id=123,
|
||||
title='digital_ocean: fix redis, elastic search start on boot, '
|
||||
'fix fd limits on supervisor, set postgres 11 version',
|
||||
description='''
|
||||
Check if we should use full-topic or mini-topic.
|
||||
|
||||
- full topic produces some problems with merge states etc
|
||||
- server-mini-topic needs probably tweeks.
|
||||
''',
|
||||
repo_name='foobar',
|
||||
source_ref_parts=AttributeDict(type='branch', name='fix-ticket-2000'),
|
||||
target_ref_parts=AttributeDict(type='branch', name='master'),
|
||||
)
|
||||
target_repo = AttributeDict(repo_name='repo_group/target_repo')
|
||||
source_repo = AttributeDict(repo_name='repo_group/source_repo')
|
||||
user = User.get_by_username(self.request.GET.get('user')) or self._rhodecode_db_user
|
||||
|
||||
email_kwargs = {
|
||||
'test': {},
|
||||
'message': {
|
||||
'body': 'message body !'
|
||||
},
|
||||
'email_test': {
|
||||
'user': user,
|
||||
'date': datetime.datetime.now(),
|
||||
'rhodecode_version': c.rhodecode_version
|
||||
},
|
||||
'password_reset': {
|
||||
'password_reset_url': 'http://example.com/reset-rhodecode-password/token',
|
||||
|
||||
'user': user,
|
||||
'date': datetime.datetime.now(),
|
||||
'email': 'test@rhodecode.com',
|
||||
'first_admin_email': User.get_first_super_admin().email
|
||||
},
|
||||
'password_reset_confirmation': {
|
||||
'new_password': 'new-password-example',
|
||||
'user': user,
|
||||
'date': datetime.datetime.now(),
|
||||
'email': 'test@rhodecode.com',
|
||||
'first_admin_email': User.get_first_super_admin().email
|
||||
},
|
||||
'registration': {
|
||||
'user': user,
|
||||
'date': datetime.datetime.now(),
|
||||
},
|
||||
|
||||
'pull_request_comment': {
|
||||
'user': user,
|
||||
|
||||
'status_change': None,
|
||||
'status_change_type': None,
|
||||
|
||||
'pull_request': pr,
|
||||
'pull_request_commits': [],
|
||||
|
||||
'pull_request_target_repo': target_repo,
|
||||
'pull_request_target_repo_url': 'http://target-repo/url',
|
||||
|
||||
'pull_request_source_repo': source_repo,
|
||||
'pull_request_source_repo_url': 'http://source-repo/url',
|
||||
|
||||
'pull_request_url': 'http://localhost/pr1',
|
||||
'pr_comment_url': 'http://comment-url',
|
||||
|
||||
'comment_file': None,
|
||||
'comment_line': None,
|
||||
'comment_type': 'note',
|
||||
'comment_body': 'This is my comment body. *I like !*',
|
||||
|
||||
'renderer_type': 'markdown',
|
||||
'mention': True,
|
||||
|
||||
},
|
||||
'pull_request_comment+status': {
|
||||
'user': user,
|
||||
|
||||
'status_change': 'approved',
|
||||
'status_change_type': 'approved',
|
||||
|
||||
'pull_request': pr,
|
||||
'pull_request_commits': [],
|
||||
|
||||
'pull_request_target_repo': target_repo,
|
||||
'pull_request_target_repo_url': 'http://target-repo/url',
|
||||
|
||||
'pull_request_source_repo': source_repo,
|
||||
'pull_request_source_repo_url': 'http://source-repo/url',
|
||||
|
||||
'pull_request_url': 'http://localhost/pr1',
|
||||
'pr_comment_url': 'http://comment-url',
|
||||
|
||||
'comment_type': 'todo',
|
||||
'comment_file': None,
|
||||
'comment_line': None,
|
||||
'comment_body': '''
|
||||
I think something like this would be better
|
||||
|
||||
```py
|
||||
|
||||
def db():
|
||||
global connection
|
||||
return connection
|
||||
|
||||
```
|
||||
|
||||
''',
|
||||
|
||||
'renderer_type': 'markdown',
|
||||
'mention': True,
|
||||
|
||||
},
|
||||
'pull_request_comment+file': {
|
||||
'user': user,
|
||||
|
||||
'status_change': None,
|
||||
'status_change_type': None,
|
||||
|
||||
'pull_request': pr,
|
||||
'pull_request_commits': [],
|
||||
|
||||
'pull_request_target_repo': target_repo,
|
||||
'pull_request_target_repo_url': 'http://target-repo/url',
|
||||
|
||||
'pull_request_source_repo': source_repo,
|
||||
'pull_request_source_repo_url': 'http://source-repo/url',
|
||||
|
||||
'pull_request_url': 'http://localhost/pr1',
|
||||
|
||||
'pr_comment_url': 'http://comment-url',
|
||||
|
||||
'comment_file': 'rhodecode/model/db.py',
|
||||
'comment_line': 'o1210',
|
||||
'comment_type': 'todo',
|
||||
'comment_body': '''
|
||||
I like this !
|
||||
|
||||
But please check this code::
|
||||
|
||||
def main():
|
||||
print 'ok'
|
||||
|
||||
This should work better !
|
||||
''',
|
||||
|
||||
'renderer_type': 'rst',
|
||||
'mention': True,
|
||||
|
||||
},
|
||||
|
||||
'cs_comment': {
|
||||
'user': user,
|
||||
'commit': AttributeDict(idx=123, raw_id='a'*40, message='Commit message'),
|
||||
'status_change': None,
|
||||
'status_change_type': None,
|
||||
|
||||
'commit_target_repo_url': 'http://foo.example.com/#comment1',
|
||||
'repo_name': 'test-repo',
|
||||
'comment_type': 'note',
|
||||
'comment_file': None,
|
||||
'comment_line': None,
|
||||
'commit_comment_url': 'http://comment-url',
|
||||
'comment_body': 'This is my comment body. *I like !*',
|
||||
'renderer_type': 'markdown',
|
||||
'mention': True,
|
||||
},
|
||||
'cs_comment+status': {
|
||||
'user': user,
|
||||
'commit': AttributeDict(idx=123, raw_id='a' * 40, message='Commit message'),
|
||||
'status_change': 'approved',
|
||||
'status_change_type': 'approved',
|
||||
|
||||
'commit_target_repo_url': 'http://foo.example.com/#comment1',
|
||||
'repo_name': 'test-repo',
|
||||
'comment_type': 'note',
|
||||
'comment_file': None,
|
||||
'comment_line': None,
|
||||
'commit_comment_url': 'http://comment-url',
|
||||
'comment_body': '''
|
||||
Hello **world**
|
||||
|
||||
This is a multiline comment :)
|
||||
|
||||
- list
|
||||
- list2
|
||||
''',
|
||||
'renderer_type': 'markdown',
|
||||
'mention': True,
|
||||
},
|
||||
'cs_comment+file': {
|
||||
'user': user,
|
||||
'commit': AttributeDict(idx=123, raw_id='a' * 40, message='Commit message'),
|
||||
'status_change': None,
|
||||
'status_change_type': None,
|
||||
|
||||
'commit_target_repo_url': 'http://foo.example.com/#comment1',
|
||||
'repo_name': 'test-repo',
|
||||
|
||||
'comment_type': 'note',
|
||||
'comment_file': 'test-file.py',
|
||||
'comment_line': 'n100',
|
||||
|
||||
'commit_comment_url': 'http://comment-url',
|
||||
'comment_body': 'This is my comment body. *I like !*',
|
||||
'renderer_type': 'markdown',
|
||||
'mention': True,
|
||||
},
|
||||
|
||||
'pull_request': {
|
||||
'user': user,
|
||||
'pull_request': pr,
|
||||
'pull_request_commits': [
|
||||
('472d1df03bf7206e278fcedc6ac92b46b01c4e21', '''\
|
||||
my-account: moved email closer to profile as it's similar data just moved outside.
|
||||
'''),
|
||||
('cbfa3061b6de2696c7161ed15ba5c6a0045f90a7', '''\
|
||||
users: description edit fixes
|
||||
|
||||
- tests
|
||||
- added metatags info
|
||||
'''),
|
||||
],
|
||||
|
||||
'pull_request_target_repo': target_repo,
|
||||
'pull_request_target_repo_url': 'http://target-repo/url',
|
||||
|
||||
'pull_request_source_repo': source_repo,
|
||||
'pull_request_source_repo_url': 'http://source-repo/url',
|
||||
|
||||
'pull_request_url': 'http://code.rhodecode.com/_pull-request/123',
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
template_type = email_id.split('+')[0]
|
||||
(c.subject, c.headers, c.email_body,
|
||||
c.email_body_plaintext) = EmailNotificationModel().render_email(
|
||||
template_type, **email_kwargs.get(email_id, {}))
|
||||
|
||||
test_email = self.request.GET.get('email')
|
||||
if test_email:
|
||||
recipients = [test_email]
|
||||
run_task(tasks.send_email, recipients, c.subject,
|
||||
c.email_body_plaintext, c.email_body)
|
||||
|
||||
if self.request.matched_route.name == 'debug_style_email_plain_rendered':
|
||||
template = 'debug_style/email_plain_rendered.mako'
|
||||
else:
|
||||
template = 'debug_style/email.mako'
|
||||
return render_to_response(
|
||||
template, self._get_template_context(c),
|
||||
request=self.request)
|
||||
|
||||
@view_config(
|
||||
route_name='debug_style_template', request_method='GET',
|
||||
renderer=None)
|
||||
|
|
@ -53,7 +323,16 @@ class DebugStyleView(BaseAppView):
|
|||
c = self.load_default_context()
|
||||
c.active = os.path.splitext(t_path)[0]
|
||||
c.came_from = ''
|
||||
c.email_types = {
|
||||
'cs_comment+file': {},
|
||||
'cs_comment+status': {},
|
||||
|
||||
'pull_request_comment+file': {},
|
||||
'pull_request_comment+status': {},
|
||||
}
|
||||
c.email_types.update(EmailNotificationModel.email_types)
|
||||
|
||||
return render_to_response(
|
||||
'debug_style/' + t_path, self._get_template_context(c),
|
||||
request=self.request)
|
||||
request=self.request)
|
||||
|
||||
|
|
|
|||
|
|
@ -98,7 +98,7 @@ class TestRepoCommitCommentsView(TestController):
|
|||
assert notification.type_ == Notification.TYPE_CHANGESET_COMMENT
|
||||
|
||||
author = notification.created_by_user.username_and_name
|
||||
sbj = '{0} left a {1} on commit `{2}` in the {3} repository'.format(
|
||||
sbj = '@{0} left a {1} on commit `{2}` in the `{3}` repository'.format(
|
||||
author, comment_type, h.show_id(commit), backend.repo_name)
|
||||
assert sbj == notification.subject
|
||||
|
||||
|
|
@ -159,7 +159,7 @@ class TestRepoCommitCommentsView(TestController):
|
|||
assert comment.revision == commit_id
|
||||
|
||||
author = notification.created_by_user.username_and_name
|
||||
sbj = '{0} left a {1} on file `{2}` in commit `{3}` in the {4} repository'.format(
|
||||
sbj = '@{0} left a {1} on file `{2}` in commit `{3}` in the `{4}` repository'.format(
|
||||
author, comment_type, f_path, h.show_id(commit), backend.repo_name)
|
||||
|
||||
assert sbj == notification.subject
|
||||
|
|
@ -230,7 +230,7 @@ class TestRepoCommitCommentsView(TestController):
|
|||
assert notification.type_ == Notification.TYPE_CHANGESET_COMMENT
|
||||
|
||||
author = notification.created_by_user.username_and_name
|
||||
sbj = '[status: Approved] {0} left a note on commit `{1}` in the {2} repository'.format(
|
||||
sbj = '[status: Approved] @{0} left a note on commit `{1}` in the `{2}` repository'.format(
|
||||
author, h.show_id(commit), backend.repo_name)
|
||||
assert sbj == notification.subject
|
||||
|
||||
|
|
|
|||
|
|
@ -467,7 +467,7 @@ class TestPullrequestsView(object):
|
|||
.filter(Notification.created_by == pull_request.author.user_id,
|
||||
Notification.type_ == Notification.TYPE_PULL_REQUEST,
|
||||
Notification.subject.contains(
|
||||
"wants you to review pull request #%s" % pull_request_id))
|
||||
"requested a pull request review. !%s" % pull_request_id))
|
||||
assert len(notifications.all()) == 1
|
||||
|
||||
# Change reviewers and check that a notification was made
|
||||
|
|
@ -549,11 +549,10 @@ class TestPullrequestsView(object):
|
|||
pull_request_id = pull_request.pull_request_id
|
||||
repo_name = pull_request.target_repo.scm_instance().name,
|
||||
|
||||
response = self.app.post(
|
||||
route_path('pullrequest_merge',
|
||||
repo_name=str(repo_name[0]),
|
||||
pull_request_id=pull_request_id),
|
||||
params={'csrf_token': csrf_token}).follow()
|
||||
url = route_path('pullrequest_merge',
|
||||
repo_name=str(repo_name[0]),
|
||||
pull_request_id=pull_request_id)
|
||||
response = self.app.post(url, params={'csrf_token': csrf_token}).follow()
|
||||
|
||||
pull_request = PullRequest.get(pull_request_id)
|
||||
|
||||
|
|
@ -735,12 +734,12 @@ class TestPullrequestsView(object):
|
|||
backend.pull_heads(source, heads=['change-rebased'])
|
||||
|
||||
# update PR
|
||||
self.app.post(
|
||||
route_path('pullrequest_update',
|
||||
repo_name=target.repo_name,
|
||||
pull_request_id=pull_request_id),
|
||||
params={'update_commits': 'true', 'csrf_token': csrf_token},
|
||||
status=200)
|
||||
url = route_path('pullrequest_update',
|
||||
repo_name=target.repo_name,
|
||||
pull_request_id=pull_request_id)
|
||||
self.app.post(url,
|
||||
params={'update_commits': 'true', 'csrf_token': csrf_token},
|
||||
status=200)
|
||||
|
||||
# check that we have now both revisions
|
||||
pull_request = PullRequest.get(pull_request_id)
|
||||
|
|
@ -801,12 +800,12 @@ class TestPullrequestsView(object):
|
|||
vcsrepo.run_git_command(['reset', '--soft', 'HEAD~2'])
|
||||
|
||||
# update PR
|
||||
self.app.post(
|
||||
route_path('pullrequest_update',
|
||||
repo_name=target.repo_name,
|
||||
pull_request_id=pull_request_id),
|
||||
params={'update_commits': 'true', 'csrf_token': csrf_token},
|
||||
status=200)
|
||||
url = route_path('pullrequest_update',
|
||||
repo_name=target.repo_name,
|
||||
pull_request_id=pull_request_id)
|
||||
self.app.post(url,
|
||||
params={'update_commits': 'true', 'csrf_token': csrf_token},
|
||||
status=200)
|
||||
|
||||
response = self.app.get(route_path('pullrequest_new', repo_name=target.repo_name))
|
||||
assert response.status_int == 200
|
||||
|
|
@ -961,12 +960,12 @@ class TestPullrequestsView(object):
|
|||
else:
|
||||
vcs.strip(pr_util.commit_ids['new-feature'])
|
||||
|
||||
response = self.app.post(
|
||||
route_path('pullrequest_update',
|
||||
repo_name=pull_request.target_repo.repo_name,
|
||||
pull_request_id=pull_request.pull_request_id),
|
||||
params={'update_commits': 'true',
|
||||
'csrf_token': csrf_token})
|
||||
url = route_path('pullrequest_update',
|
||||
repo_name=pull_request.target_repo.repo_name,
|
||||
pull_request_id=pull_request.pull_request_id)
|
||||
response = self.app.post(url,
|
||||
params={'update_commits': 'true',
|
||||
'csrf_token': csrf_token})
|
||||
|
||||
assert response.status_int == 200
|
||||
assert response.body == 'true'
|
||||
|
|
@ -1208,14 +1207,11 @@ class TestPullrequestsControllerDelete(object):
|
|||
|
||||
|
||||
def assert_pull_request_status(pull_request, expected_status):
|
||||
status = ChangesetStatusModel().calculated_review_status(
|
||||
pull_request=pull_request)
|
||||
status = ChangesetStatusModel().calculated_review_status(pull_request=pull_request)
|
||||
assert status == expected_status
|
||||
|
||||
|
||||
@pytest.mark.parametrize('route', ['pullrequest_new', 'pullrequest_create'])
|
||||
@pytest.mark.usefixtures("autologin_user")
|
||||
def test_forbidde_to_repo_summary_for_svn_repositories(backend_svn, app, route):
|
||||
response = app.get(
|
||||
route_path(route, repo_name=backend_svn.repo_name), status=404)
|
||||
|
||||
app.get(route_path(route, repo_name=backend_svn.repo_name), status=404)
|
||||
|
|
|
|||
|
|
@ -359,7 +359,7 @@ class CommentsModel(BaseModel):
|
|||
kwargs.update({
|
||||
'commit': commit_obj,
|
||||
'commit_message': commit_obj.message,
|
||||
'commit_target_repo': target_repo_url,
|
||||
'commit_target_repo_url': target_repo_url,
|
||||
'commit_comment_url': commit_comment_url,
|
||||
})
|
||||
|
||||
|
|
@ -382,6 +382,11 @@ class CommentsModel(BaseModel):
|
|||
pull_request_id=pull_request_obj.pull_request_id,
|
||||
_anchor='comment-%s' % comment.comment_id)
|
||||
|
||||
pr_url = h.route_url(
|
||||
'pullrequest_show',
|
||||
repo_name=pr_target_repo.repo_name,
|
||||
pull_request_id=pull_request_obj.pull_request_id, )
|
||||
|
||||
# set some variables for email notification
|
||||
pr_target_repo_url = h.route_url(
|
||||
'repo_summary', repo_name=pr_target_repo.repo_name)
|
||||
|
|
@ -393,10 +398,11 @@ class CommentsModel(BaseModel):
|
|||
kwargs.update({
|
||||
'pull_request': pull_request_obj,
|
||||
'pr_id': pull_request_obj.pull_request_id,
|
||||
'pr_target_repo': pr_target_repo,
|
||||
'pr_target_repo_url': pr_target_repo_url,
|
||||
'pr_source_repo': pr_source_repo,
|
||||
'pr_source_repo_url': pr_source_repo_url,
|
||||
'pull_request_url': pr_url,
|
||||
'pull_request_target_repo': pr_target_repo,
|
||||
'pull_request_target_repo_url': pr_target_repo_url,
|
||||
'pull_request_source_repo': pr_source_repo,
|
||||
'pull_request_source_repo_url': pr_source_repo_url,
|
||||
'pr_comment_url': pr_comment_url,
|
||||
'pr_closing': closing_pr,
|
||||
})
|
||||
|
|
|
|||
|
|
@ -1110,8 +1110,8 @@ class PullRequestModel(BaseModel):
|
|||
pr_target_repo = pull_request_obj.target_repo
|
||||
|
||||
pr_url = h.route_url('pullrequest_show',
|
||||
repo_name=pr_target_repo.repo_name,
|
||||
pull_request_id=pull_request_obj.pull_request_id,)
|
||||
repo_name=pr_target_repo.repo_name,
|
||||
pull_request_id=pull_request_obj.pull_request_id,)
|
||||
|
||||
# set some variables for email notification
|
||||
pr_target_repo_url = h.route_url(
|
||||
|
|
|
|||
|
|
@ -612,7 +612,8 @@ class UserModel(BaseModel):
|
|||
'password_reset_url': pwd_reset_url,
|
||||
'user': user,
|
||||
'email': user_email,
|
||||
'date': datetime.datetime.now()
|
||||
'date': datetime.datetime.now(),
|
||||
'first_admin_email': User.get_first_super_admin().email
|
||||
}
|
||||
|
||||
(subject, headers, email_body,
|
||||
|
|
@ -670,7 +671,8 @@ class UserModel(BaseModel):
|
|||
'new_password': new_passwd,
|
||||
'user': user,
|
||||
'email': user_email,
|
||||
'date': datetime.datetime.now()
|
||||
'date': datetime.datetime.now(),
|
||||
'first_admin_email': User.get_first_super_admin().email
|
||||
}
|
||||
|
||||
(subject, headers, email_body,
|
||||
|
|
|
|||
|
|
@ -342,6 +342,8 @@ function registerRCRoutes() {
|
|||
pyroutes.register('gist_show_formatted', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s', ['gist_id', 'revision', 'format']);
|
||||
pyroutes.register('gist_show_formatted_path', '/_admin/gists/%(gist_id)s/%(revision)s/%(format)s/%(f_path)s', ['gist_id', 'revision', 'format', 'f_path']);
|
||||
pyroutes.register('debug_style_home', '/_admin/debug_style', []);
|
||||
pyroutes.register('debug_style_email', '/_admin/debug_style/email/%(email_id)s', ['email_id']);
|
||||
pyroutes.register('debug_style_email_plain_rendered', '/_admin/debug_style/email-rendered/%(email_id)s', ['email_id']);
|
||||
pyroutes.register('debug_style_template', '/_admin/debug_style/t/%(t_path)s', ['t_path']);
|
||||
pyroutes.register('apiv2', '/_admin/api', []);
|
||||
pyroutes.register('admin_settings_license', '/_admin/settings/license', []);
|
||||
|
|
|
|||
29
rhodecode/templates/debug_style/email.mako
Normal file
29
rhodecode/templates/debug_style/email.mako
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
|
||||
|
||||
<html>
|
||||
<head></head>
|
||||
|
||||
<body>
|
||||
|
||||
SUBJECT:
|
||||
<pre>${c.subject}</pre>
|
||||
|
||||
HEADERS:
|
||||
<pre>
|
||||
${c.headers}
|
||||
</pre>
|
||||
|
||||
PLAINTEXT:
|
||||
<pre>
|
||||
${c.email_body_plaintext|n}
|
||||
</pre>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
<br/><br/>
|
||||
|
||||
HTML:
|
||||
|
||||
${c.email_body|n}
|
||||
|
||||
|
||||
49
rhodecode/templates/debug_style/email_plain_rendered.mako
Normal file
49
rhodecode/templates/debug_style/email_plain_rendered.mako
Normal file
|
|
@ -0,0 +1,49 @@
|
|||
## -*- coding: utf-8 -*-
|
||||
<%inherit file="/base/base.mako"/>
|
||||
|
||||
<%def name="title()">
|
||||
${_('Show notification')} ${c.rhodecode_user.username}
|
||||
%if c.rhodecode_name:
|
||||
· ${h.branding(c.rhodecode_name)}
|
||||
%endif
|
||||
</%def>
|
||||
|
||||
<%def name="breadcrumbs_links()">
|
||||
${h.link_to(_('My Notifications'), h.route_path('notifications_show_all'))}
|
||||
»
|
||||
${_('Show notification')}
|
||||
</%def>
|
||||
|
||||
<%def name="menu_bar_nav()">
|
||||
${self.menu_items(active='admin')}
|
||||
</%def>
|
||||
|
||||
<%def name="main()">
|
||||
<div class="box">
|
||||
|
||||
<!-- box / title -->
|
||||
<div class="title">
|
||||
Rendered plain text using markup renderer
|
||||
</div>
|
||||
<div class="table">
|
||||
<div >
|
||||
<div class="notification-header">
|
||||
GRAVATAR
|
||||
<div class="desc">
|
||||
DESC
|
||||
</div>
|
||||
</div>
|
||||
<div class="notification-body">
|
||||
<div class="notification-subject">
|
||||
<h3>${_('Subject')}: ${c.subject}</h3>
|
||||
</div>
|
||||
${c.email_body|n}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</%def>
|
||||
|
||||
|
||||
|
||||
34
rhodecode/templates/debug_style/emails.html
Normal file
34
rhodecode/templates/debug_style/emails.html
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
## -*- coding: utf-8 -*-
|
||||
<%inherit file="/debug_style/index.html"/>
|
||||
|
||||
<%def name="breadcrumbs_links()">
|
||||
${h.link_to(_('Style'), h.route_path('debug_style_home'))}
|
||||
»
|
||||
${c.active}
|
||||
</%def>
|
||||
|
||||
|
||||
<%def name="real_main()">
|
||||
<div class="box">
|
||||
<div class="title">
|
||||
${self.breadcrumbs()}
|
||||
</div>
|
||||
|
||||
<div class='sidebar-col-wrapper'>
|
||||
${self.sidebar()}
|
||||
<div class="main-content">
|
||||
<h2>Emails</h2>
|
||||
<ul>
|
||||
% for elem in sorted(c.email_types.keys()):
|
||||
<li>
|
||||
<a href="${request.route_path('debug_style_email', email_id=elem, _query={'user':c.rhodecode_user.username})}">${elem}</a>
|
||||
|
|
||||
<a href="${request.route_path('debug_style_email_plain_rendered', email_id=elem, _query={'user':c.rhodecode_user.username})}">plain rendered</a>
|
||||
</li>
|
||||
% endfor
|
||||
</ul>
|
||||
|
||||
</div> <!-- .main-content -->
|
||||
</div>
|
||||
</div> <!-- .box -->
|
||||
</%def>
|
||||
|
|
@ -52,6 +52,7 @@
|
|||
<div class="sidebar">
|
||||
<ul class="nav nav-pills nav-stacked">
|
||||
<li class="${'active' if c.active=='index' else ''}"><a href="${h.route_path('debug_style_home')}">${_('Index')}</a></li>
|
||||
<li class="${'active' if c.active=='emails' else ''}"><a href="${h.route_path('debug_style_template', t_path='emails.html')}">${_('Emails')}</a></li>
|
||||
<li class="${'active' if c.active=='typography' else ''}"><a href="${h.route_path('debug_style_template', t_path='typography.html')}">${_('Typography')}</a></li>
|
||||
<li class="${'active' if c.active=='forms' else ''}"><a href="${h.route_path('debug_style_template', t_path='forms.html')}">${_('Forms')}</a></li>
|
||||
<li class="${'active' if c.active=='buttons' else ''}"><a href="${h.route_path('debug_style_template', t_path='buttons.html')}">${_('Buttons')}</a></li>
|
||||
|
|
|
|||
|
|
@ -2,15 +2,23 @@
|
|||
|
||||
## helpers
|
||||
<%def name="tag_button(text, tag_type=None)">
|
||||
<%
|
||||
color_scheme = {
|
||||
'default': 'border:1px solid #979797;color:#666666;background-color:#f9f9f9',
|
||||
'approved': 'border:1px solid #0ac878;color:#0ac878;background-color:#f9f9f9',
|
||||
'rejected': 'border:1px solid #e85e4d;color:#e85e4d;background-color:#f9f9f9',
|
||||
'under_review': 'border:1px solid #ffc854;color:#ffc854;background-color:#f9f9f9',
|
||||
}
|
||||
%>
|
||||
<pre style="display:inline;border-radius:2px;font-size:12px;padding:.2em;${color_scheme.get(tag_type, color_scheme['default'])}">${text}</pre>
|
||||
<%
|
||||
color_scheme = {
|
||||
'default': 'border:1px solid #979797;color:#666666;background-color:#f9f9f9',
|
||||
'approved': 'border:1px solid #0ac878;color:#0ac878;background-color:#f9f9f9',
|
||||
'rejected': 'border:1px solid #e85e4d;color:#e85e4d;background-color:#f9f9f9',
|
||||
'under_review': 'border:1px solid #ffc854;color:#ffc854;background-color:#f9f9f9',
|
||||
}
|
||||
|
||||
css_style = ';'.join([
|
||||
'display:inline',
|
||||
'border-radius:2px',
|
||||
'font-size:12px',
|
||||
'padding:.2em',
|
||||
])
|
||||
|
||||
%>
|
||||
<pre style="${css_style}; ${color_scheme.get(tag_type, color_scheme['default'])}">${text}</pre>
|
||||
</%def>
|
||||
|
||||
<%def name="status_text(text, tag_type=None)">
|
||||
|
|
@ -25,6 +33,34 @@
|
|||
<span style="font-weight:bold;font-size:12px;padding:.2em;${color_scheme.get(tag_type, color_scheme['default'])}">${text}</span>
|
||||
</%def>
|
||||
|
||||
<%def name="gravatar_img(email, size=16)">
|
||||
<%
|
||||
css_style = ';'.join([
|
||||
'padding: 0',
|
||||
'margin: -4px 0',
|
||||
'border-radius: 50%',
|
||||
'box-sizing: content-box',
|
||||
'display: inline',
|
||||
'line-height: 1em',
|
||||
'min-width: 16px',
|
||||
'min-height: 16px',
|
||||
])
|
||||
%>
|
||||
|
||||
<img alt="gravatar" style="${css_style}" src="${h.gravatar_url(email, size)}" height="${size}" width="${size}">
|
||||
</%def>
|
||||
|
||||
<%def name="link_css()">\
|
||||
<%
|
||||
css_style = ';'.join([
|
||||
'color:#427cc9',
|
||||
'text-decoration:none',
|
||||
'cursor:pointer'
|
||||
])
|
||||
%>\
|
||||
${css_style}\
|
||||
</%def>
|
||||
|
||||
## Constants
|
||||
<%
|
||||
text_regular = "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif;"
|
||||
|
|
@ -35,8 +71,8 @@ text_monospace = "'Menlo', 'Liberation Mono', 'Consolas', 'DejaVu Sans Mono', 'U
|
|||
## headers we additionally can set for email
|
||||
<%def name="headers()" filter="n,trim"></%def>
|
||||
|
||||
<%def name="plaintext_footer()">
|
||||
${_('This is a notification from RhodeCode. %(instance_url)s') % {'instance_url': instance_url}}
|
||||
<%def name="plaintext_footer()" filter="trim">
|
||||
${_('This is a notification from RhodeCode.')} ${instance_url}
|
||||
</%def>
|
||||
|
||||
<%def name="body_plaintext()" filter="n,trim">
|
||||
|
|
@ -52,36 +88,122 @@ ${self.plaintext_footer()}
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
|
||||
<title>${self.subject()}</title>
|
||||
<style type="text/css">
|
||||
/* Based on The MailChimp Reset INLINE: Yes. */
|
||||
#outlook a {padding:0;} /* Force Outlook to provide a "view in browser" menu link. */
|
||||
body{width:100% !important; -webkit-text-size-adjust:100%; -ms-text-size-adjust:100%; margin:0; padding:0; font-family: ${text_regular|n}}
|
||||
/* Prevent Webkit and Windows Mobile platforms from changing default font sizes.*/
|
||||
.ExternalClass {width:100%;} /* Force Hotmail to display emails at full width */
|
||||
.ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div {line-height: 100%;}
|
||||
/* Forces Hotmail to display normal line spacing. More on that: http://www.emailonacid.com/forum/viewthread/43/ */
|
||||
#backgroundTable {margin:0; padding:0; line-height: 100% !important;}
|
||||
/* Based on The MailChimp Reset INLINE: Yes. */
|
||||
#outlook a {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
/* Force Outlook to provide a "view in browser" menu link. */
|
||||
body {
|
||||
width: 100% !important;
|
||||
-webkit-text-size-adjust: 100%;
|
||||
-ms-text-size-adjust: 100%;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: ${text_regular|n}
|
||||
}
|
||||
|
||||
/* Prevent Webkit and Windows Mobile platforms from changing default font sizes.*/
|
||||
.ExternalClass {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
/* Force Hotmail to display emails at full width */
|
||||
.ExternalClass, .ExternalClass p, .ExternalClass span, .ExternalClass font, .ExternalClass td, .ExternalClass div {
|
||||
line-height: 100%;
|
||||
}
|
||||
|
||||
/* Forces Hotmail to display normal line spacing. More on that: http://www.emailonacid.com/forum/viewthread/43/ */
|
||||
#backgroundTable {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
line-height: 100% !important;
|
||||
}
|
||||
|
||||
/* End reset */
|
||||
|
||||
/* defaults for images*/
|
||||
img {outline:none; text-decoration:none; -ms-interpolation-mode: bicubic;}
|
||||
a img {border:none;}
|
||||
.image_fix {display:block;}
|
||||
img {
|
||||
outline: none;
|
||||
text-decoration: none;
|
||||
-ms-interpolation-mode: bicubic;
|
||||
}
|
||||
|
||||
a img {
|
||||
border: none;
|
||||
}
|
||||
|
||||
.image_fix {
|
||||
display: block;
|
||||
}
|
||||
|
||||
body {
|
||||
line-height: 1.2em;
|
||||
}
|
||||
|
||||
p {
|
||||
margin: 0 0 20px;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5, h6 {
|
||||
color: #323232 !important;
|
||||
}
|
||||
|
||||
a {
|
||||
color: #427cc9;
|
||||
text-decoration: none;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
a:focus {
|
||||
outline: none;
|
||||
}
|
||||
|
||||
a:hover {
|
||||
color: #305b91;
|
||||
}
|
||||
|
||||
h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {
|
||||
color: #427cc9 !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
||||
h1 a:active, h2 a:active, h3 a:active, h4 a:active, h5 a:active, h6 a:active {
|
||||
color: #305b91 !important;
|
||||
}
|
||||
|
||||
h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited {
|
||||
color: #305b91 !important;
|
||||
}
|
||||
|
||||
table {
|
||||
font-size: 13px;
|
||||
border-collapse: collapse;
|
||||
mso-table-lspace: 0pt;
|
||||
mso-table-rspace: 0pt;
|
||||
}
|
||||
|
||||
table td {
|
||||
padding: .65em 1em .65em 0;
|
||||
border-collapse: collapse;
|
||||
vertical-align: top;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
input {
|
||||
display: inline;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #dbd9da;
|
||||
padding: .5em;
|
||||
}
|
||||
|
||||
input:focus {
|
||||
outline: 1px solid #979797
|
||||
}
|
||||
|
||||
body {line-height:1.2em;}
|
||||
p {margin: 0 0 20px;}
|
||||
h1, h2, h3, h4, h5, h6 {color:#323232!important;}
|
||||
a {color:#427cc9;text-decoration:none;outline:none;cursor:pointer;}
|
||||
a:focus {outline:none;}
|
||||
a:hover {color: #305b91;}
|
||||
h1 a, h2 a, h3 a, h4 a, h5 a, h6 a {color:#427cc9!important;text-decoration:none!important;}
|
||||
h1 a:active, h2 a:active, h3 a:active, h4 a:active, h5 a:active, h6 a:active {color: #305b91!important;}
|
||||
h1 a:visited, h2 a:visited, h3 a:visited, h4 a:visited, h5 a:visited, h6 a:visited {color: #305b91!important;}
|
||||
table {font-size:13px;border-collapse:collapse;mso-table-lspace:0pt;mso-table-rspace:0pt;}
|
||||
table td {padding:.65em 1em .65em 0;border-collapse:collapse;vertical-align:top;text-align:left;}
|
||||
input {display:inline;border-radius:2px;border-style:solid;border: 1px solid #dbd9da;padding:.5em;}
|
||||
input:focus {outline: 1px solid #979797}
|
||||
@media only screen and (-webkit-min-device-pixel-ratio: 2) {
|
||||
/* Put your iPhone 4g styles in here */
|
||||
/* Put your iPhone 4g styles in here */
|
||||
}
|
||||
|
||||
/* Android targeting */
|
||||
|
|
@ -96,6 +218,262 @@ ${self.plaintext_footer()}
|
|||
}
|
||||
/* end Android targeting */
|
||||
|
||||
/** MARKDOWN styling **/
|
||||
div.markdown-block {
|
||||
clear: both;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
padding: 3px 5px 3px
|
||||
}
|
||||
|
||||
div.markdown-block h1, div.markdown-block h2, div.markdown-block h3, div.markdown-block h4, div.markdown-block h5, div.markdown-block h6 {
|
||||
border-bottom: none !important;
|
||||
padding: 0 !important;
|
||||
overflow: visible !important
|
||||
}
|
||||
|
||||
div.markdown-block h1, div.markdown-block h2 {
|
||||
border-bottom: 1px #e6e5e5 solid !important
|
||||
}
|
||||
|
||||
div.markdown-block h1 {
|
||||
font-size: 32px;
|
||||
margin: 15px 0 15px 0 !important;
|
||||
padding-bottom: 5px !important
|
||||
}
|
||||
|
||||
div.markdown-block h2 {
|
||||
font-size: 24px !important;
|
||||
margin: 34px 0 10px 0 !important;
|
||||
padding-top: 15px !important;
|
||||
padding-bottom: 8px !important
|
||||
}
|
||||
|
||||
div.markdown-block h3 {
|
||||
font-size: 18px !important;
|
||||
margin: 30px 0 8px 0 !important;
|
||||
padding-bottom: 2px !important
|
||||
}
|
||||
|
||||
div.markdown-block h4 {
|
||||
font-size: 13px !important;
|
||||
margin: 18px 0 3px 0 !important
|
||||
}
|
||||
|
||||
div.markdown-block h5 {
|
||||
font-size: 12px !important;
|
||||
margin: 15px 0 3px 0 !important
|
||||
}
|
||||
|
||||
div.markdown-block h6 {
|
||||
font-size: 12px;
|
||||
color: #777777;
|
||||
margin: 15px 0 3px 0 !important
|
||||
}
|
||||
|
||||
div.markdown-block hr {
|
||||
border: 0;
|
||||
color: #e6e5e5;
|
||||
background-color: #e6e5e5;
|
||||
height: 3px;
|
||||
margin-bottom: 13px
|
||||
}
|
||||
|
||||
div.markdown-block ol, div.markdown-block ul, div.markdown-block p, div.markdown-block blockquote, div.markdown-block dl, div.markdown-block li, div.markdown-block table {
|
||||
margin: 3px 0 13px 0 !important;
|
||||
color: #424242 !important;
|
||||
font-size: 13px !important;
|
||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen-Sans, Ubuntu, Cantarell, "Helvetica Neue", sans-serif;
|
||||
font-weight: normal !important;
|
||||
overflow: visible !important;
|
||||
line-height: 140% !important
|
||||
}
|
||||
|
||||
div.markdown-block pre {
|
||||
margin: 3px 0 13px 0 !important;
|
||||
padding: .5em;
|
||||
color: #424242 !important;
|
||||
font-size: 13px !important;
|
||||
overflow: visible !important;
|
||||
line-height: 140% !important;
|
||||
background-color: #F5F5F5
|
||||
}
|
||||
|
||||
div.markdown-block img {
|
||||
border-style: none;
|
||||
background-color: #fff;
|
||||
padding-right: 20px;
|
||||
max-width: 100%
|
||||
}
|
||||
|
||||
div.markdown-block strong {
|
||||
font-weight: 600;
|
||||
margin: 0
|
||||
}
|
||||
|
||||
div.markdown-block ul.checkbox, div.markdown-block ol.checkbox {
|
||||
padding-left: 20px !important;
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 18px !important
|
||||
}
|
||||
|
||||
div.markdown-block ul, div.markdown-block ol {
|
||||
padding-left: 30px !important;
|
||||
margin-top: 0 !important;
|
||||
margin-bottom: 18px !important
|
||||
}
|
||||
|
||||
div.markdown-block ul.checkbox li, div.markdown-block ol.checkbox li {
|
||||
list-style: none !important;
|
||||
margin: 6px !important;
|
||||
padding: 0 !important
|
||||
}
|
||||
|
||||
div.markdown-block ul li, div.markdown-block ol li {
|
||||
list-style: disc !important;
|
||||
margin: 6px !important;
|
||||
padding: 0 !important
|
||||
}
|
||||
|
||||
div.markdown-block ol li {
|
||||
list-style: decimal !important
|
||||
}
|
||||
|
||||
div.markdown-block #message {
|
||||
-webkit-border-radius: 2px;
|
||||
-moz-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #dbd9da;
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: 60px;
|
||||
margin: 6px 0
|
||||
}
|
||||
|
||||
div.markdown-block button, div.markdown-block #ws {
|
||||
font-size: 13px;
|
||||
padding: 4px 6px;
|
||||
-webkit-border-radius: 2px;
|
||||
-moz-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
border: 1px solid #dbd9da;
|
||||
background-color: #eeeeee
|
||||
}
|
||||
|
||||
div.markdown-block code, div.markdown-block pre, div.markdown-block #ws, div.markdown-block #message {
|
||||
font-family: 'Menlo', 'Liberation Mono', 'Consolas', 'DejaVu Sans Mono', 'Ubuntu Mono', 'Courier New', 'andale mono', 'lucida console', monospace;
|
||||
font-size: 11px;
|
||||
-webkit-border-radius: 2px;
|
||||
-moz-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
background-color: white;
|
||||
color: #7E7F7F
|
||||
}
|
||||
|
||||
div.markdown-block code {
|
||||
border: 1px solid #eeeeee;
|
||||
margin: 0 2px;
|
||||
padding: 0 5px
|
||||
}
|
||||
|
||||
div.markdown-block pre {
|
||||
border: 1px solid #dbd9da;
|
||||
overflow: auto;
|
||||
padding: .5em;
|
||||
background-color: #F5F5F5
|
||||
}
|
||||
|
||||
div.markdown-block pre > code {
|
||||
border: 0;
|
||||
margin: 0;
|
||||
padding: 0
|
||||
}
|
||||
|
||||
div.rst-block {
|
||||
clear: both;
|
||||
overflow: hidden;
|
||||
margin: 0;
|
||||
padding: 3px 5px 3px
|
||||
}
|
||||
|
||||
div.rst-block h2 {
|
||||
font-weight: normal
|
||||
}
|
||||
|
||||
div.rst-block h1, div.rst-block h2, div.rst-block h3, div.rst-block h4, div.rst-block h5, div.rst-block h6 {
|
||||
border-bottom: 0 !important;
|
||||
margin: 0 !important;
|
||||
padding: 0 !important;
|
||||
line-height: 1.5em !important
|
||||
}
|
||||
|
||||
div.rst-block h1:first-child {
|
||||
padding-top: .25em !important
|
||||
}
|
||||
|
||||
div.rst-block h2, div.rst-block h3 {
|
||||
margin: 1em 0 !important
|
||||
}
|
||||
|
||||
div.rst-block h1, div.rst-block h2 {
|
||||
border-bottom: 1px #e6e5e5 solid !important
|
||||
}
|
||||
|
||||
div.rst-block h2 {
|
||||
margin-top: 1.5em !important;
|
||||
padding-top: .5em !important
|
||||
}
|
||||
|
||||
div.rst-block p {
|
||||
color: black !important;
|
||||
margin: 1em 0 !important;
|
||||
line-height: 1.5em !important
|
||||
}
|
||||
|
||||
div.rst-block ul {
|
||||
list-style: disc !important;
|
||||
margin: 1em 0 1em 2em !important;
|
||||
clear: both
|
||||
}
|
||||
|
||||
div.rst-block ol {
|
||||
list-style: decimal;
|
||||
margin: 1em 0 1em 2em !important
|
||||
}
|
||||
|
||||
div.rst-block pre, div.rst-block code {
|
||||
font: 12px "Bitstream Vera Sans Mono", "Courier", monospace
|
||||
}
|
||||
|
||||
div.rst-block code {
|
||||
font-size: 12px !important;
|
||||
background-color: ghostWhite !important;
|
||||
color: #444 !important;
|
||||
padding: 0 .2em !important;
|
||||
border: 1px solid #dedede !important
|
||||
}
|
||||
|
||||
div.rst-block pre code {
|
||||
padding: 0 !important;
|
||||
font-size: 12px !important;
|
||||
background-color: #eee !important;
|
||||
border: none !important
|
||||
}
|
||||
|
||||
div.rst-block pre {
|
||||
margin: 1em 0;
|
||||
padding: 15px;
|
||||
border: 1px solid #eeeeee;
|
||||
-webkit-border-radius: 2px;
|
||||
-moz-border-radius: 2px;
|
||||
border-radius: 2px;
|
||||
overflow: auto;
|
||||
font-size: 12px;
|
||||
color: #444;
|
||||
background-color: #F5F5F5
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
|
||||
<!-- Targeting Windows Mobile -->
|
||||
|
|
@ -106,26 +484,30 @@ ${self.plaintext_footer()}
|
|||
<![endif]-->
|
||||
|
||||
<!--[if gte mso 9]>
|
||||
<style>
|
||||
/* Target Outlook 2007 and 2010 */
|
||||
</style>
|
||||
<style>
|
||||
/* Target Outlook 2007 and 2010 */
|
||||
</style>
|
||||
<![endif]-->
|
||||
</head>
|
||||
<body>
|
||||
<!-- Wrapper/Container Table: Use a wrapper table to control the width and the background color consistently of your email. Use this approach instead of setting attributes on the body tag. -->
|
||||
<table cellpadding="0" cellspacing="0" border="0" id="backgroundTable" align="left" style="margin:1%;width:97%;padding:0;font-family:sans-serif;font-weight:100;border:1px solid #dbd9da">
|
||||
<tr>
|
||||
<td valign="top" style="padding:0;">
|
||||
<td valign="top" style="padding:0;">
|
||||
<table cellpadding="0" cellspacing="0" border="0" align="left" width="100%">
|
||||
<tr><td style="width:100%;padding:7px;background-color:#202020" valign="top">
|
||||
<a style="color:#eeeeee;text-decoration:none;" href="${instance_url}">
|
||||
${_('RhodeCode')}
|
||||
% if rhodecode_instance_name:
|
||||
- ${rhodecode_instance_name}
|
||||
% endif
|
||||
</a>
|
||||
</td></tr>
|
||||
<tr><td style="padding:15px;" valign="top">${self.body()}</td></tr>
|
||||
<tr>
|
||||
<td style="width:100%;padding:10px 15px;background-color:#202020" valign="top">
|
||||
<a style="color:#eeeeee;text-decoration:none;" href="${instance_url}">
|
||||
${_('RhodeCode')}
|
||||
% if rhodecode_instance_name:
|
||||
- ${rhodecode_instance_name}
|
||||
% endif
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding:15px;" valign="top">${self.body()}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td>
|
||||
</tr>
|
||||
|
|
@ -133,10 +515,11 @@ ${self.plaintext_footer()}
|
|||
<!-- End of wrapper table -->
|
||||
|
||||
<div style="clear: both"></div>
|
||||
<p>
|
||||
<a style="margin-top:15px;margin-left:1%;font-weight:100;font-size:11px;color:#666666;text-decoration:none;font-family:${text_monospace} " href="${instance_url}">
|
||||
${self.plaintext_footer()}
|
||||
</a>
|
||||
</p>
|
||||
<div style="margin-left:1%;font-weight:100;font-size:11px;color:#666666;text-decoration:none;font-family:${text_monospace}">
|
||||
${_('This is a notification from RhodeCode.')}
|
||||
<a style="font-weight:100;font-size:11px;color:#666666;text-decoration:none;font-family:${text_monospace}" href="${instance_url}">
|
||||
${instance_url}
|
||||
</a>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
|||
|
|
@ -6,24 +6,25 @@
|
|||
<%def name="subject()" filter="n,trim,whitespace_filter">
|
||||
<%
|
||||
data = {
|
||||
'user': h.person(user),
|
||||
'user': '@'+h.person(user),
|
||||
'repo_name': repo_name,
|
||||
'commit_id': h.show_id(commit),
|
||||
'status': status_change,
|
||||
'comment_file': comment_file,
|
||||
'comment_line': comment_line,
|
||||
'comment_type': comment_type,
|
||||
|
||||
'commit_id': h.show_id(commit),
|
||||
}
|
||||
%>
|
||||
${_('[mention]') if mention else ''} \
|
||||
|
||||
|
||||
% if comment_file:
|
||||
${_('{user} left a {comment_type} on file `{comment_file}` in commit `{commit_id}`').format(**data)} ${_('in the {repo_name} repository').format(**data) |n}
|
||||
${(_('[mention]') if mention else '')} ${_('{user} left a {comment_type} on file `{comment_file}` in commit `{commit_id}`').format(**data)} ${_('in the `{repo_name}` repository').format(**data) |n}
|
||||
% else:
|
||||
% if status_change:
|
||||
${_('[status: {status}] {user} left a {comment_type} on commit `{commit_id}`').format(**data) |n} ${_('in the {repo_name} repository').format(**data) |n}
|
||||
${(_('[mention]') if mention else '')} ${_('[status: {status}] {user} left a {comment_type} on commit `{commit_id}`').format(**data) |n} ${_('in the `{repo_name}` repository').format(**data) |n}
|
||||
% else:
|
||||
${_('{user} left a {comment_type} on commit `{commit_id}`').format(**data) |n} ${_('in the {repo_name} repository').format(**data) |n}
|
||||
${(_('[mention]') if mention else '')} ${_('{user} left a {comment_type} on commit `{commit_id}`').format(**data) |n} ${_('in the `{repo_name}` repository').format(**data) |n}
|
||||
% endif
|
||||
% endif
|
||||
|
||||
|
|
@ -35,31 +36,38 @@ ${_('[mention]') if mention else ''} \
|
|||
data = {
|
||||
'user': h.person(user),
|
||||
'repo_name': repo_name,
|
||||
'commit_id': h.show_id(commit),
|
||||
'status': status_change,
|
||||
'comment_file': comment_file,
|
||||
'comment_line': comment_line,
|
||||
'comment_type': comment_type,
|
||||
|
||||
'commit_id': h.show_id(commit),
|
||||
}
|
||||
%>
|
||||
${self.subject()}
|
||||
|
||||
* ${_('Comment link')}: ${commit_comment_url}
|
||||
|
||||
%if status_change:
|
||||
* ${_('Commit status')}: ${_('Status was changed to')}: *${status_change}*
|
||||
|
||||
%endif
|
||||
* ${_('Commit')}: ${h.show_id(commit)}
|
||||
|
||||
* ${_('Commit message')}: ${commit.message}
|
||||
|
||||
%if comment_file:
|
||||
* ${_('File: {comment_file} on line {comment_line}').format(**data)}
|
||||
|
||||
%endif
|
||||
% if comment_type == 'todo':
|
||||
${_('`TODO` comment')}:
|
||||
% else:
|
||||
${_('`Note` comment')}:
|
||||
% endif
|
||||
|
||||
${comment_body |n, trim}
|
||||
|
||||
---
|
||||
|
||||
%if status_change:
|
||||
${_('Commit status was changed to')}: *${status_change}*
|
||||
%endif
|
||||
|
||||
${comment_body|n}
|
||||
|
||||
${self.plaintext_footer()}
|
||||
</%def>
|
||||
|
||||
|
|
@ -67,42 +75,87 @@ ${self.plaintext_footer()}
|
|||
<%
|
||||
data = {
|
||||
'user': h.person(user),
|
||||
'repo': commit_target_repo,
|
||||
'repo_name': repo_name,
|
||||
'commit_id': h.show_id(commit),
|
||||
'comment_file': comment_file,
|
||||
'comment_line': comment_line,
|
||||
'comment_type': comment_type,
|
||||
'renderer_type': renderer_type or 'plain',
|
||||
|
||||
'repo': commit_target_repo_url,
|
||||
'repo_name': repo_name,
|
||||
'commit_id': h.show_id(commit),
|
||||
}
|
||||
%>
|
||||
<table style="text-align:left;vertical-align:middle;">
|
||||
<tr><td colspan="2" style="width:100%;padding-bottom:15px;border-bottom:1px solid #dbd9da;">
|
||||
|
||||
% if comment_file:
|
||||
<h4><a href="${commit_comment_url}" style="color:#427cc9;text-decoration:none;cursor:pointer">${_('{user} left a {comment_type} on file `{comment_file}` in commit `{commit_id}`').format(**data)}</a> ${_('in the {repo} repository').format(**data) |n}</h4>
|
||||
% else:
|
||||
<h4><a href="${commit_comment_url}" style="color:#427cc9;text-decoration:none;cursor:pointer">${_('{user} left a {comment_type} on commit `{commit_id}`').format(**data) |n}</a> ${_('in the {repo} repository').format(**data) |n}</h4>
|
||||
% endif
|
||||
</td></tr>
|
||||
<table style="text-align:left;vertical-align:middle;width: 100%">
|
||||
<tr>
|
||||
<td style="width:100%;border-bottom:1px solid #dbd9da;">
|
||||
|
||||
<tr><td style="padding-right:20px;padding-top:15px;">${_('Commit')}</td><td style="padding-top:15px;"><a href="${commit_comment_url}" style="color:#427cc9;text-decoration:none;cursor:pointer">${h.show_id(commit)}</a></td></tr>
|
||||
<tr><td style="padding-right:20px;">${_('Description')}</td><td style="white-space:pre-wrap">${h.urlify_commit_message(commit.message, repo_name)}</td></tr>
|
||||
<h4 style="margin: 0">
|
||||
<div style="margin-bottom: 4px; color:#7E7F7F">
|
||||
@${h.person(user.username)}
|
||||
</div>
|
||||
${_('left a')}
|
||||
<a href="${commit_comment_url}" style="${base.link_css()}">
|
||||
% if comment_file:
|
||||
${_('{comment_type} on file `{comment_file}` in commit.').format(**data)}
|
||||
% else:
|
||||
${_('{comment_type} on commit.').format(**data) |n}
|
||||
% endif
|
||||
</a>
|
||||
<div style="margin-top: 10px"></div>
|
||||
${_('Commit')} <code>${data['commit_id']}</code> ${_('of repository')}: ${data['repo_name']}
|
||||
</h4>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<table style="text-align:left;vertical-align:middle;width: 100%">
|
||||
|
||||
## spacing def
|
||||
<tr>
|
||||
<td style="width: 130px"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
% if status_change:
|
||||
<tr>
|
||||
<td style="padding-right:20px;">${_('Status')}</td>
|
||||
<td style="padding-right:20px;">${_('Commit Status')}:</td>
|
||||
<td>
|
||||
${_('The commit status was changed to')}: ${base.status_text(status_change, tag_type=status_change_type)}
|
||||
${_('Status was changed to')}: ${base.status_text(status_change, tag_type=status_change_type)}
|
||||
</td>
|
||||
</tr>
|
||||
% endif
|
||||
|
||||
<tr>
|
||||
<td style="padding-right:20px;">
|
||||
<td style="padding-right:20px;">${_('Commit')}:</td>
|
||||
<td>
|
||||
<a href="${commit_comment_url}" style="${base.link_css()}">${h.show_id(commit)}</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-right:20px;">${_('Commit message')}:</td>
|
||||
<td style="white-space:pre-wrap">${h.urlify_commit_message(commit.message, repo_name)}</td>
|
||||
</tr>
|
||||
|
||||
% if comment_file:
|
||||
<tr>
|
||||
<td style="padding-right:20px;">${_('File')}:</td>
|
||||
<td><a href="${commit_comment_url}" style="${base.link_css()}">${_('`{comment_file}` on line {comment_line}').format(**data)}</a></td>
|
||||
</tr>
|
||||
% endif
|
||||
|
||||
<tr style="background-image: linear-gradient(to right, black 33%, rgba(255,255,255,0) 0%);background-position: bottom;background-size: 3px 1px;background-repeat: repeat-x;">
|
||||
<td colspan="2" style="padding-right:20px;">
|
||||
% if comment_type == 'todo':
|
||||
${(_('TODO comment on line: {comment_line}') if comment_file else _('TODO comment')).format(**data)}
|
||||
${_('`TODO` comment')}:
|
||||
% else:
|
||||
${(_('Note comment on line: {comment_line}') if comment_file else _('Note comment')).format(**data)}
|
||||
${_('`Note` comment')}:
|
||||
% endif
|
||||
</td>
|
||||
<td style="line-height:1.2em;white-space:pre-wrap">${h.render(comment_body, renderer=renderer_type, mentions=True)}</td></tr>
|
||||
</tr>
|
||||
|
||||
<td colspan="2" style="background: #F7F7F7">${h.render(comment_body, renderer=data['renderer_type'], mentions=True)}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
## -*- coding: utf-8 -*-
|
||||
<%inherit file="base.mako"/>
|
||||
<%namespace name="base" file="base.mako"/>
|
||||
|
||||
<%def name="subject()" filter="n,trim,whitespace_filter">
|
||||
RhodeCode test email: ${h.format_date(date)}
|
||||
|
|
@ -7,7 +8,13 @@ RhodeCode test email: ${h.format_date(date)}
|
|||
|
||||
## plain text version of the email. Empty by default
|
||||
<%def name="body_plaintext()" filter="n,trim">
|
||||
Test Email from RhodeCode version: ${rhodecode_version}, sent by: ${user}
|
||||
Test Email from RhodeCode version: ${rhodecode_version}
|
||||
Email sent by: ${h.person(user)}
|
||||
|
||||
---
|
||||
${self.plaintext_footer()}
|
||||
</%def>
|
||||
|
||||
${body_plaintext()}
|
||||
Test Email from RhodeCode version: ${rhodecode_version}
|
||||
<br/><br/>
|
||||
Email sent by: <strong>${h.person(user)}</strong>
|
||||
|
|
|
|||
|
|
@ -9,13 +9,13 @@
|
|||
<%def name="body_plaintext()" filter="n,trim">
|
||||
${body}
|
||||
|
||||
---
|
||||
${self.plaintext_footer()}
|
||||
</%def>
|
||||
|
||||
## BODY GOES BELOW
|
||||
<table style="text-align:left;vertical-align:top;">
|
||||
<tr><td style="padding-right:20px;padding-top:15px;white-space:pre-wrap">${body}</td></tr>
|
||||
<tr>
|
||||
<td style="padding-right:20px;padding-top:15px;white-space:pre-wrap">${body}</td>
|
||||
</tr>
|
||||
</table>
|
||||
<p><a style="margin-top:15px;margin-left:1%;font-family:sans-serif;font-weight:100;font-size:11px;display:block;color:#666666;text-decoration:none;" href="${instance_url}">
|
||||
${self.plaintext_footer()}
|
||||
</a></p>
|
||||
|
|
@ -1,5 +1,6 @@
|
|||
## -*- coding: utf-8 -*-
|
||||
<%inherit file="base.mako"/>
|
||||
<%namespace name="base" file="base.mako"/>
|
||||
|
||||
<%def name="subject()" filter="n,trim,whitespace_filter">
|
||||
RhodeCode Password reset
|
||||
|
|
@ -7,16 +8,18 @@ RhodeCode Password reset
|
|||
|
||||
## plain text version of the email. Empty by default
|
||||
<%def name="body_plaintext()" filter="n,trim">
|
||||
Hi ${user.username},
|
||||
Hello ${user.username},
|
||||
|
||||
There was a request to reset your password using the email address ${email} on ${h.format_date(date)}
|
||||
On ${h.format_date(date)} there was a request to reset your password using the email address `${email}`
|
||||
|
||||
*If you didn't do this, please contact your RhodeCode administrator.*
|
||||
*If you did not request a password reset, please contact your RhodeCode administrator at: ${first_admin_email}*
|
||||
|
||||
You can continue, and generate new password by clicking following URL:
|
||||
${password_reset_url}
|
||||
|
||||
This link will be active for 10 minutes.
|
||||
|
||||
---
|
||||
${self.plaintext_footer()}
|
||||
</%def>
|
||||
|
||||
|
|
@ -24,10 +27,11 @@ ${self.plaintext_footer()}
|
|||
<p>
|
||||
Hello ${user.username},
|
||||
</p><p>
|
||||
There was a request to reset your password using the email address ${email} on ${h.format_date(date)}
|
||||
<br/>
|
||||
<strong>If you did not request a password reset, please contact your RhodeCode administrator.</strong>
|
||||
On ${h.format_date(date)} there was a request to reset your password using the email address `${email}`
|
||||
<br/><br/>
|
||||
<strong>If you did not request a password reset, please contact your RhodeCode administrator at: ${first_admin_email}.</strong>
|
||||
</p><p>
|
||||
<a href="${password_reset_url}">${_('Generate new password here')}.</a>
|
||||
This link will be active for 10 minutes.
|
||||
You can continue, and generate new password by clicking following URL:<br/><br/>
|
||||
<a href="${password_reset_url}" style="${base.link_css()}">${password_reset_url}</a>
|
||||
<br/><br/>This link will be active for 10 minutes.
|
||||
</p>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
## -*- coding: utf-8 -*-
|
||||
<%inherit file="base.mako"/>
|
||||
<%namespace name="base" file="base.mako"/>
|
||||
|
||||
<%def name="subject()" filter="n,trim,whitespace_filter">
|
||||
Your new RhodeCode password
|
||||
|
|
@ -7,14 +8,15 @@ Your new RhodeCode password
|
|||
|
||||
## plain text version of the email. Empty by default
|
||||
<%def name="body_plaintext()" filter="n,trim">
|
||||
Hi ${user.username},
|
||||
Hello ${user.username},
|
||||
|
||||
Below is your new access password for RhodeCode.
|
||||
Below is your new access password for RhodeCode requested via password reset link.
|
||||
|
||||
*If you didn't do this, please contact your RhodeCode administrator.*
|
||||
*If you did not request a password reset, please contact your RhodeCode administrator at: ${first_admin_email}.*
|
||||
|
||||
password: ${new_password}
|
||||
new password: ${new_password}
|
||||
|
||||
---
|
||||
${self.plaintext_footer()}
|
||||
</%def>
|
||||
|
||||
|
|
@ -22,8 +24,8 @@ ${self.plaintext_footer()}
|
|||
<p>
|
||||
Hello ${user.username},
|
||||
</p><p>
|
||||
Below is your new access password for RhodeCode.
|
||||
<br/>
|
||||
<strong>If you didn't request a new password, please contact your RhodeCode administrator.</strong>
|
||||
Below is your new access password for RhodeCode requested via password reset link.
|
||||
<br/><br/>
|
||||
<strong>If you did not request a password reset, please contact your RhodeCode administrator at: ${first_admin_email}.</strong>
|
||||
</p>
|
||||
<p>password: <pre>${new_password}</pre>
|
||||
<p>new password: <code>${new_password}</code>
|
||||
|
|
|
|||
|
|
@ -6,27 +6,29 @@
|
|||
<%def name="subject()" filter="n,trim,whitespace_filter">
|
||||
<%
|
||||
data = {
|
||||
'user': h.person(user),
|
||||
'pr_title': pull_request.title,
|
||||
'pr_id': pull_request.pull_request_id,
|
||||
'user': '@'+h.person(user),
|
||||
'repo_name': repo_name,
|
||||
'status': status_change,
|
||||
'comment_file': comment_file,
|
||||
'comment_line': comment_line,
|
||||
'comment_type': comment_type,
|
||||
|
||||
'pr_title': pull_request.title,
|
||||
'pr_id': pull_request.pull_request_id,
|
||||
}
|
||||
%>
|
||||
|
||||
${(_('[mention]') if mention else '')} \
|
||||
|
||||
% if comment_file:
|
||||
${_('{user} left a {comment_type} on file `{comment_file}` in pull request #{pr_id} "{pr_title}"').format(**data) |n}
|
||||
${(_('[mention]') if mention else '')} ${_('{user} left a {comment_type} on file `{comment_file}` in pull request !{pr_id}: "{pr_title}"').format(**data) |n}
|
||||
% else:
|
||||
% if status_change:
|
||||
${_('[status: {status}] {user} left a {comment_type} on pull request #{pr_id} "{pr_title}"').format(**data) |n}
|
||||
${(_('[mention]') if mention else '')} ${_('[status: {status}] {user} left a {comment_type} on pull request !{pr_id}: "{pr_title}"').format(**data) |n}
|
||||
% else:
|
||||
${_('{user} left a {comment_type} on pull request #{pr_id} "{pr_title}"').format(**data) |n}
|
||||
${(_('[mention]') if mention else '')} ${_('{user} left a {comment_type} on pull request !{pr_id}: "{pr_title}"').format(**data) |n}
|
||||
% endif
|
||||
% endif
|
||||
|
||||
</%def>
|
||||
|
||||
## PLAINTEXT VERSION OF BODY
|
||||
|
|
@ -34,34 +36,51 @@ ${(_('[mention]') if mention else '')} \
|
|||
<%
|
||||
data = {
|
||||
'user': h.person(user),
|
||||
'pr_title': pull_request.title,
|
||||
'pr_id': pull_request.pull_request_id,
|
||||
'repo_name': repo_name,
|
||||
'status': status_change,
|
||||
'comment_file': comment_file,
|
||||
'comment_line': comment_line,
|
||||
'comment_type': comment_type,
|
||||
|
||||
'pr_title': pull_request.title,
|
||||
'pr_id': pull_request.pull_request_id,
|
||||
'source_ref_type': pull_request.source_ref_parts.type,
|
||||
'source_ref_name': pull_request.source_ref_parts.name,
|
||||
'target_ref_type': pull_request.target_ref_parts.type,
|
||||
'target_ref_name': pull_request.target_ref_parts.name,
|
||||
'source_repo': pull_request_source_repo.repo_name,
|
||||
'target_repo': pull_request_target_repo.repo_name,
|
||||
'source_repo_url': pull_request_source_repo_url,
|
||||
'target_repo_url': pull_request_target_repo_url,
|
||||
}
|
||||
%>
|
||||
${self.subject()}
|
||||
|
||||
${h.literal(_('Pull request !{pr_id}: `{pr_title}`').format(**data))}
|
||||
|
||||
* ${h.literal(_('Commit flow: {source_ref_type}:{source_ref_name} of {source_repo_url} into {target_ref_type}:{target_ref_name} of {target_repo_url}').format(**data))}
|
||||
|
||||
* ${_('Comment link')}: ${pr_comment_url}
|
||||
|
||||
* ${_('Source repository')}: ${pr_source_repo_url}
|
||||
%if status_change and not closing_pr:
|
||||
* ${_('{user} submitted pull request !{pr_id} status: *{status}*').format(**data)}
|
||||
|
||||
%elif status_change and closing_pr:
|
||||
* ${_('{user} submitted pull request !{pr_id} status: *{status} and closed*').format(**data)}
|
||||
|
||||
%if comment_file:
|
||||
* ${_('File: {comment_file} on line {comment_line}').format(comment_file=comment_file, comment_line=comment_line)}
|
||||
%endif
|
||||
%if comment_file:
|
||||
* ${_('File: {comment_file} on line {comment_line}').format(**data)}
|
||||
|
||||
%endif
|
||||
% if comment_type == 'todo':
|
||||
${_('`TODO` comment')}:
|
||||
% else:
|
||||
${_('`Note` comment')}:
|
||||
% endif
|
||||
|
||||
${comment_body |n, trim}
|
||||
|
||||
---
|
||||
|
||||
%if status_change and not closing_pr:
|
||||
${_('{user} submitted pull request #{pr_id} status: *{status}*').format(**data)}
|
||||
%elif status_change and closing_pr:
|
||||
${_('{user} submitted pull request #{pr_id} status: *{status} and closed*').format(**data)}
|
||||
%endif
|
||||
|
||||
${comment_body |n}
|
||||
|
||||
${self.plaintext_footer()}
|
||||
</%def>
|
||||
|
||||
|
|
@ -69,46 +88,104 @@ ${self.plaintext_footer()}
|
|||
<%
|
||||
data = {
|
||||
'user': h.person(user),
|
||||
'pr_title': pull_request.title,
|
||||
'pr_id': pull_request.pull_request_id,
|
||||
'status': status_change,
|
||||
'comment_file': comment_file,
|
||||
'comment_line': comment_line,
|
||||
'comment_type': comment_type,
|
||||
'renderer_type': renderer_type or 'plain',
|
||||
|
||||
'pr_title': pull_request.title,
|
||||
'pr_id': pull_request.pull_request_id,
|
||||
'status': status_change,
|
||||
'source_ref_type': pull_request.source_ref_parts.type,
|
||||
'source_ref_name': pull_request.source_ref_parts.name,
|
||||
'target_ref_type': pull_request.target_ref_parts.type,
|
||||
'target_ref_name': pull_request.target_ref_parts.name,
|
||||
'source_repo': pull_request_source_repo.repo_name,
|
||||
'target_repo': pull_request_target_repo.repo_name,
|
||||
'source_repo_url': h.link_to(pull_request_source_repo.repo_name, pull_request_source_repo_url),
|
||||
'target_repo_url': h.link_to(pull_request_target_repo.repo_name, pull_request_target_repo_url),
|
||||
}
|
||||
%>
|
||||
<table style="text-align:left;vertical-align:middle;">
|
||||
<tr><td colspan="2" style="width:100%;padding-bottom:15px;border-bottom:1px solid #dbd9da;">
|
||||
|
||||
% if comment_file:
|
||||
<h4><a href="${pr_comment_url}" style="color:#427cc9;text-decoration:none;cursor:pointer">${_('{user} left a {comment_type} on file `{comment_file}` in pull request #{pr_id} "{pr_title}"').format(**data) |n}</a></h4>
|
||||
% else:
|
||||
<h4><a href="${pr_comment_url}" style="color:#427cc9;text-decoration:none;cursor:pointer">${_('{user} left a {comment_type} on pull request #{pr_id} "{pr_title}"').format(**data) |n}</a></h4>
|
||||
% endif
|
||||
<table style="text-align:left;vertical-align:middle;width: 100%">
|
||||
<tr>
|
||||
<td style="width:100%;border-bottom:1px solid #dbd9da;">
|
||||
|
||||
</td></tr>
|
||||
<tr><td style="padding-right:20px;padding-top:15px;">${_('Source')}</td><td style="padding-top:15px;"><a style="color:#427cc9;text-decoration:none;cursor:pointer" href="${pr_source_repo_url}">${pr_source_repo.repo_name}</a></td></tr>
|
||||
<h4 style="margin: 0">
|
||||
<div style="margin-bottom: 4px; color:#7E7F7F">
|
||||
@${h.person(user.username)}
|
||||
</div>
|
||||
${_('left a')}
|
||||
<a href="${pr_comment_url}" style="${base.link_css()}">
|
||||
% if comment_file:
|
||||
${_('{comment_type} on file `{comment_file}` in pull request.').format(**data)}
|
||||
% else:
|
||||
${_('{comment_type} on pull request.').format(**data) |n}
|
||||
% endif
|
||||
</a>
|
||||
<div style="margin-top: 10px"></div>
|
||||
${_('Pull request')} <code>!${data['pr_id']}: ${data['pr_title']}</code>
|
||||
</h4>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<table style="text-align:left;vertical-align:middle;width: 100%">
|
||||
|
||||
## spacing def
|
||||
<tr>
|
||||
<td style="width: 130px"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
% if status_change:
|
||||
<tr>
|
||||
<td style="padding-right:20px;">${_('Status')}</td>
|
||||
<td>
|
||||
% if closing_pr:
|
||||
${_('Closed pull request with status')}: ${base.status_text(status_change, tag_type=status_change_type)}
|
||||
% else:
|
||||
${_('Submitted review status')}: ${base.status_text(status_change, tag_type=status_change_type)}
|
||||
% endif
|
||||
</td>
|
||||
</tr>
|
||||
% endif
|
||||
<tr>
|
||||
<td style="padding-right:20px;">
|
||||
% if comment_type == 'todo':
|
||||
${(_('TODO comment on line: {comment_line}') if comment_file else _('TODO comment')).format(**data)}
|
||||
<td style="padding-right:20px;">${_('Review Status')}:</td>
|
||||
<td>
|
||||
% if closing_pr:
|
||||
${_('Closed pull request with status')}: ${base.status_text(status_change, tag_type=status_change_type)}
|
||||
% else:
|
||||
${(_('Note comment on line: {comment_line}') if comment_file else _('Note comment')).format(**data)}
|
||||
${_('Submitted review status')}: ${base.status_text(status_change, tag_type=status_change_type)}
|
||||
% endif
|
||||
</td>
|
||||
<td style="line-height:1.2em;white-space:pre-wrap">${h.render(comment_body, renderer=renderer_type, mentions=True)}</td>
|
||||
</tr>
|
||||
% endif
|
||||
|
||||
<tr>
|
||||
<td style="padding-right:20px;line-height:20px;">${_('Commit Flow')}:</td>
|
||||
<td style="line-height:20px;">
|
||||
${base.tag_button('{}:{}'.format(data['source_ref_type'], pull_request.source_ref_parts.name))} ${_('of')} ${data['source_repo_url']}
|
||||
→
|
||||
${base.tag_button('{}:{}'.format(data['target_ref_type'], pull_request.target_ref_parts.name))} ${_('of')} ${data['target_repo_url']}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-right:20px;">${_('Pull request')}:</td>
|
||||
<td>
|
||||
<a href="${pull_request_url}" style="${base.link_css()}">
|
||||
!${pull_request.pull_request_id}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
% if comment_file:
|
||||
<tr>
|
||||
<td style="padding-right:20px;">${_('File')}:</td>
|
||||
<td><a href="${pr_comment_url}" style="${base.link_css()}">${_('`{comment_file}` on line {comment_line}').format(**data)}</a></td>
|
||||
</tr>
|
||||
% endif
|
||||
|
||||
<tr style="background-image: linear-gradient(to right, black 33%, rgba(255,255,255,0) 0%);background-position: bottom;background-size: 3px 1px;background-repeat: repeat-x;">
|
||||
<td colspan="2" style="padding-right:20px;">
|
||||
% if comment_type == 'todo':
|
||||
${_('`TODO` comment')}:
|
||||
% else:
|
||||
${_('`Note` comment')}:
|
||||
% endif
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<td colspan="2" style="background: #F7F7F7">${h.render(comment_body, renderer=data['renderer_type'], mentions=True)}</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
|||
|
|
@ -2,19 +2,20 @@
|
|||
<%inherit file="base.mako"/>
|
||||
<%namespace name="base" file="base.mako"/>
|
||||
|
||||
## EMAIL SUBJECT
|
||||
<%def name="subject()" filter="n,trim,whitespace_filter">
|
||||
<%
|
||||
data = {
|
||||
'user': h.person(user),
|
||||
'user': '@'+h.person(user),
|
||||
'pr_id': pull_request.pull_request_id,
|
||||
'pr_title': pull_request.title,
|
||||
}
|
||||
%>
|
||||
|
||||
${_('%(user)s wants you to review pull request #%(pr_id)s: "%(pr_title)s"') % data |n}
|
||||
${_('{user} requested a pull request review. !{pr_id}: "{pr_title}"').format(**data) |n}
|
||||
</%def>
|
||||
|
||||
|
||||
## PLAINTEXT VERSION OF BODY
|
||||
<%def name="body_plaintext()" filter="n,trim">
|
||||
<%
|
||||
data = {
|
||||
|
|
@ -25,32 +26,36 @@ data = {
|
|||
'source_ref_name': pull_request.source_ref_parts.name,
|
||||
'target_ref_type': pull_request.target_ref_parts.type,
|
||||
'target_ref_name': pull_request.target_ref_parts.name,
|
||||
'repo_url': pull_request_source_repo_url
|
||||
'repo_url': pull_request_source_repo_url,
|
||||
'source_repo': pull_request_source_repo.repo_name,
|
||||
'target_repo': pull_request_target_repo.repo_name,
|
||||
'source_repo_url': pull_request_source_repo_url,
|
||||
'target_repo_url': pull_request_target_repo_url,
|
||||
}
|
||||
%>
|
||||
${self.subject()}
|
||||
|
||||
${h.literal(_('Pull request !{pr_id}: `{pr_title}`').format(**data))}
|
||||
|
||||
${h.literal(_('Pull request from %(source_ref_type)s:%(source_ref_name)s of %(repo_url)s into %(target_ref_type)s:%(target_ref_name)s') % data)}
|
||||
* ${h.literal(_('Commit flow: {source_ref_type}:{source_ref_name} of {source_repo_url} into {target_ref_type}:{target_ref_name} of {target_repo_url}').format(**data))}
|
||||
|
||||
|
||||
* ${_('Link')}: ${pull_request_url}
|
||||
* ${_('Pull Request link')}: ${pull_request_url}
|
||||
|
||||
* ${_('Title')}: ${pull_request.title}
|
||||
|
||||
* ${_('Description')}:
|
||||
|
||||
${pull_request.description}
|
||||
${pull_request.description | trim}
|
||||
|
||||
|
||||
* ${_ungettext('Commit (%(num)s)', 'Commits (%(num)s)', len(pull_request_commits) ) % {'num': len(pull_request_commits)}}:
|
||||
|
||||
% for commit_id, message in pull_request_commits:
|
||||
- ${h.short_id(commit_id)}
|
||||
${h.chop_at_smart(message, '\n', suffix_if_chopped='...')}
|
||||
- ${h.short_id(commit_id)}
|
||||
${h.chop_at_smart(message, '\n', suffix_if_chopped='...')}
|
||||
|
||||
% endfor
|
||||
|
||||
---
|
||||
${self.plaintext_footer()}
|
||||
</%def>
|
||||
<%
|
||||
|
|
@ -63,23 +68,77 @@ data = {
|
|||
'target_ref_type': pull_request.target_ref_parts.type,
|
||||
'target_ref_name': pull_request.target_ref_parts.name,
|
||||
'repo_url': pull_request_source_repo_url,
|
||||
'source_repo': pull_request_source_repo.repo_name,
|
||||
'target_repo': pull_request_target_repo.repo_name,
|
||||
'source_repo_url': h.link_to(pull_request_source_repo.repo_name, pull_request_source_repo_url),
|
||||
'target_repo_url': h.link_to(pull_request_target_repo.repo_name, pull_request_target_repo_url)
|
||||
'target_repo_url': h.link_to(pull_request_target_repo.repo_name, pull_request_target_repo_url),
|
||||
}
|
||||
%>
|
||||
<table style="text-align:left;vertical-align:middle;">
|
||||
<tr><td colspan="2" style="width:100%;padding-bottom:15px;border-bottom:1px solid #dbd9da;"><h4><a href="${pull_request_url}" style="color:#427cc9;text-decoration:none;cursor:pointer">${_('%(user)s wants you to review pull request #%(pr_id)s: "%(pr_title)s".') % data }</a></h4></td></tr>
|
||||
<tr><td style="padding-right:20px;padding-top:15px;">${_('Title')}</td><td style="padding-top:15px;">${pull_request.title}</td></tr>
|
||||
<tr><td style="padding-right:20px;">${_('Source')}</td><td>${base.tag_button(pull_request.source_ref_parts.name)} ${h.literal(_('%(source_ref_type)s of %(source_repo_url)s') % data)}</td></tr>
|
||||
<tr><td style="padding-right:20px;">${_('Target')}</td><td>${base.tag_button(pull_request.target_ref_parts.name)} ${h.literal(_('%(target_ref_type)s of %(target_repo_url)s') % data)}</td></tr>
|
||||
<tr><td style="padding-right:20px;">${_('Description')}</td><td style="white-space:pre-wrap">${pull_request.description}</td></tr>
|
||||
<tr><td style="padding-right:20px;">${_ungettext('%(num)s Commit', '%(num)s Commits', len(pull_request_commits)) % {'num': len(pull_request_commits)}}</td>
|
||||
<td><ol style="margin:0 0 0 1em;padding:0;text-align:left;">
|
||||
% for commit_id, message in pull_request_commits:
|
||||
<li style="margin:0 0 1em;"><pre style="margin:0 0 .5em">${h.short_id(commit_id)}</pre>
|
||||
${h.chop_at_smart(message, '\n', suffix_if_chopped='...')}
|
||||
</li>
|
||||
% endfor
|
||||
</ol></td>
|
||||
|
||||
<table style="text-align:left;vertical-align:middle;width: 100%">
|
||||
<tr>
|
||||
<td style="width:100%;border-bottom:1px solid #dbd9da;">
|
||||
|
||||
<h4 style="margin: 0">
|
||||
<div style="margin-bottom: 4px; color:#7E7F7F">
|
||||
@${h.person(user.username)}
|
||||
</div>
|
||||
${_('requested a')}
|
||||
<a href="${pull_request_url}" style="${base.link_css()}">
|
||||
${_('pull request review.').format(**data) }
|
||||
</a>
|
||||
<div style="margin-top: 10px"></div>
|
||||
${_('Pull request')} <code>!${data['pr_id']}: ${data['pr_title']}</code>
|
||||
</h4>
|
||||
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
</table>
|
||||
|
||||
<table style="text-align:left;vertical-align:middle;width: 100%">
|
||||
## spacing def
|
||||
<tr>
|
||||
<td style="width: 130px"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td style="padding-right:20px;line-height:20px;">${_('Commit Flow')}:</td>
|
||||
<td style="line-height:20px;">
|
||||
${base.tag_button('{}:{}'.format(data['source_ref_type'], pull_request.source_ref_parts.name))} ${_('of')} ${data['source_repo_url']}
|
||||
→
|
||||
${base.tag_button('{}:{}'.format(data['target_ref_type'], pull_request.target_ref_parts.name))} ${_('of')} ${data['target_repo_url']}
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td style="padding-right:20px;">${_('Pull request')}:</td>
|
||||
<td>
|
||||
<a href="${pull_request_url}" style="${base.link_css()}">
|
||||
!${pull_request.pull_request_id}
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-right:20px;">${_('Description')}:</td>
|
||||
<td style="white-space:pre-wrap"><code>${pull_request.description | trim}</code></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-right:20px;">${_ungettext('Commit (%(num)s)', 'Commits (%(num)s)', len(pull_request_commits)) % {'num': len(pull_request_commits)}}:</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<ol style="margin:0 0 0 1em;padding:0;text-align:left;">
|
||||
% for commit_id, message in pull_request_commits:
|
||||
<li style="margin:0 0 1em;">
|
||||
<pre style="margin:0 0 .5em"><a href="${h.route_path('repo_commit', repo_name=pull_request_source_repo.repo_name, commit_id=commit_id)}" style="${base.link_css()}">${h.short_id(commit_id)}</a></pre>
|
||||
${h.chop_at_smart(message, '\n', suffix_if_chopped='...')}
|
||||
</li>
|
||||
% endfor
|
||||
</ol>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
|||
|
|
@ -15,7 +15,8 @@ Email Plaintext Body
|
|||
</%def>
|
||||
|
||||
## BODY GOES BELOW
|
||||
<b>Email Body</b>
|
||||
|
||||
${h.short_id('0' * 40)}
|
||||
${_('Translation')}
|
||||
<strong>Email Body</strong>
|
||||
<br/>
|
||||
<br/>
|
||||
`h.short_id()`: ${h.short_id('0' * 40)}<br/>
|
||||
${_('Translation String')}<br/>
|
||||
|
|
|
|||
|
|
@ -1,5 +1,6 @@
|
|||
## -*- coding: utf-8 -*-
|
||||
<%inherit file="base.mako"/>
|
||||
<%namespace name="base" file="base.mako"/>
|
||||
|
||||
<%def name="subject()" filter="n,trim,whitespace_filter">
|
||||
RhodeCode new user registration: ${user.username}
|
||||
|
|
@ -14,14 +15,45 @@ A new user `${user.username}` has registered on ${h.format_date(date)}
|
|||
- Email: ${user.email}
|
||||
- Profile link: ${h.route_url('user_profile', username=user.username)}
|
||||
|
||||
---
|
||||
${self.plaintext_footer()}
|
||||
</%def>
|
||||
|
||||
## BODY GOES BELOW
|
||||
<table style="text-align:left;vertical-align:middle;">
|
||||
<tr><td colspan="2" style="width:100%;padding-bottom:15px;border-bottom:1px solid #dbd9da;"><h4><a href="${h.route_url('user_profile', username=user.username)}" style="color:#427cc9;text-decoration:none;cursor:pointer">${_('New user %(user)s has registered on %(date)s') % {'user': user.username, 'date': h.format_date(date)}}</a></h4></td></tr>
|
||||
<tr><td style="padding-right:20px;padding-top:20px;">${_('Username')}</td><td style="line-height:1;padding-top:20px;"><img style="margin-bottom:-5px;text-align:left;border:1px solid #dbd9da" src="${h.gravatar_url(user.email, 16)}" height="16" width="16"> ${user.username}</td></tr>
|
||||
<tr><td style="padding-right:20px;">${_('Full Name')}</td><td>${user.first_name} ${user.last_name}</td></tr>
|
||||
<tr><td style="padding-right:20px;">${_('Email')}</td><td>${user.email}</td></tr>
|
||||
<tr><td style="padding-right:20px;">${_('Profile')}</td><td><a href="${h.route_url('user_profile', username=user.username)}">${h.route_url('user_profile', username=user.username)}</a></td></tr>
|
||||
</table>
|
||||
|
||||
<table style="text-align:left;vertical-align:middle;width: 100%">
|
||||
<tr>
|
||||
<td style="width:100%;border-bottom:1px solid #dbd9da;">
|
||||
<h4 style="margin: 0">
|
||||
<a href="${h.route_url('user_profile', username=user.username)}" style="${base.link_css()}">
|
||||
${_('New user {user} has registered on {date}').format(user=user.username, date=h.format_date(date))}
|
||||
</a>
|
||||
</h4>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table style="text-align:left;vertical-align:middle;width: 100%">
|
||||
## spacing def
|
||||
<tr>
|
||||
<td style="width: 130px"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-right:20px;padding-top:20px;">${_('Username')}:</td>
|
||||
<td style="line-height:1;padding-top:20px;">${user.username}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-right:20px;">${_('Full Name')}:</td>
|
||||
<td>${user.first_name} ${user.last_name}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-right:20px;">${_('Email')}:</td>
|
||||
<td>${user.email}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-right:20px;">${_('Profile')}:</td>
|
||||
<td>
|
||||
<a href="${h.route_url('user_profile', username=user.username)}">${h.route_url('user_profile', username=user.username)}</a>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
|
|
|||
|
|
@ -1,4 +1,3 @@
|
|||
import collections
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright (C) 2010-2019 RhodeCode GmbH
|
||||
|
|
@ -20,9 +19,11 @@ import collections
|
|||
# and proprietary license terms, please see https://rhodecode.com/licenses/
|
||||
|
||||
import pytest
|
||||
import collections
|
||||
|
||||
from rhodecode.lib.partial_renderer import PyramidPartialRenderer
|
||||
from rhodecode.lib.utils2 import AttributeDict
|
||||
from rhodecode.model.db import User
|
||||
from rhodecode.model.notification import EmailNotificationModel
|
||||
|
||||
|
||||
|
|
@ -47,29 +48,26 @@ def test_render_email(app, http_host_only_stub):
|
|||
assert body_plaintext == 'Email Plaintext Body'
|
||||
|
||||
# body
|
||||
notification_footer = 'This is a notification from RhodeCode. http://%s/' \
|
||||
% http_host_only_stub
|
||||
assert notification_footer in body
|
||||
notification_footer1 = 'This is a notification from RhodeCode.'
|
||||
notification_footer2 = 'http://{}/'.format(http_host_only_stub)
|
||||
assert notification_footer1 in body
|
||||
assert notification_footer2 in body
|
||||
assert 'Email Body' in body
|
||||
|
||||
|
||||
def test_render_pr_email(app, user_admin):
|
||||
|
||||
ref = collections.namedtuple('Ref',
|
||||
'name, type')(
|
||||
'fxies123', 'book'
|
||||
)
|
||||
ref = collections.namedtuple(
|
||||
'Ref', 'name, type')('fxies123', 'book')
|
||||
|
||||
pr = collections.namedtuple('PullRequest',
|
||||
'pull_request_id, title, description, source_ref_parts, source_ref_name, target_ref_parts, target_ref_name')(
|
||||
200, 'Example Pull Request', 'Desc of PR', ref, 'bookmark', ref, 'Branch')
|
||||
|
||||
source_repo = target_repo = collections.namedtuple('Repo',
|
||||
'type, repo_name')(
|
||||
'hg', 'pull_request_1')
|
||||
source_repo = target_repo = collections.namedtuple(
|
||||
'Repo', 'type, repo_name')('hg', 'pull_request_1')
|
||||
|
||||
kwargs = {
|
||||
'user': '<marcin@rhodecode.com> Marcin Kuzminski',
|
||||
'user': User.get_first_super_admin(),
|
||||
'pull_request': pr,
|
||||
'pull_request_commits': [],
|
||||
|
||||
|
|
@ -86,7 +84,7 @@ def test_render_pr_email(app, user_admin):
|
|||
EmailNotificationModel.TYPE_PULL_REQUEST, **kwargs)
|
||||
|
||||
# subject
|
||||
assert subject == 'Marcin Kuzminski wants you to review pull request #200: "Example Pull Request"'
|
||||
assert subject == '@test_admin (RhodeCode Admin) requested a pull request review. !200: "Example Pull Request"'
|
||||
|
||||
|
||||
@pytest.mark.parametrize('mention', [
|
||||
|
|
@ -98,24 +96,21 @@ def test_render_pr_email(app, user_admin):
|
|||
EmailNotificationModel.TYPE_PULL_REQUEST_COMMENT
|
||||
])
|
||||
def test_render_comment_subject_no_newlines(app, mention, email_type):
|
||||
ref = collections.namedtuple('Ref',
|
||||
'name, type')(
|
||||
'fxies123', 'book'
|
||||
)
|
||||
ref = collections.namedtuple(
|
||||
'Ref', 'name, type')('fxies123', 'book')
|
||||
|
||||
pr = collections.namedtuple('PullRequest',
|
||||
'pull_request_id, title, description, source_ref_parts, source_ref_name, target_ref_parts, target_ref_name')(
|
||||
200, 'Example Pull Request', 'Desc of PR', ref, 'bookmark', ref, 'Branch')
|
||||
|
||||
source_repo = target_repo = collections.namedtuple('Repo',
|
||||
'type, repo_name')(
|
||||
'hg', 'pull_request_1')
|
||||
source_repo = target_repo = collections.namedtuple(
|
||||
'Repo', 'type, repo_name')('hg', 'pull_request_1')
|
||||
|
||||
kwargs = {
|
||||
'user': '<marcin@rhodecode.com> Marcin Kuzminski',
|
||||
'user': User.get_first_super_admin(),
|
||||
'commit': AttributeDict(raw_id='a'*40, message='Commit message'),
|
||||
'status_change': 'approved',
|
||||
'commit_target_repo': AttributeDict(),
|
||||
'commit_target_repo_url': 'http://foo.example.com/#comment1',
|
||||
'repo_name': 'test-repo',
|
||||
'comment_file': 'test-file.py',
|
||||
'comment_line': 'n100',
|
||||
|
|
@ -126,8 +121,6 @@ def test_render_comment_subject_no_newlines(app, mention, email_type):
|
|||
'mention': mention,
|
||||
|
||||
'pr_comment_url': 'http://comment-url',
|
||||
'pr_source_repo': AttributeDict(repo_name='foobar'),
|
||||
'pr_source_repo_url': 'http://soirce-repo/url',
|
||||
'pull_request': pr,
|
||||
'pull_request_commits': [],
|
||||
|
||||
|
|
@ -136,6 +129,8 @@ def test_render_comment_subject_no_newlines(app, mention, email_type):
|
|||
|
||||
'pull_request_source_repo': source_repo,
|
||||
'pull_request_source_repo_url': 'x',
|
||||
|
||||
'pull_request_url': 'http://code.rc.com/_pr/123'
|
||||
}
|
||||
subject, headers, body, body_plaintext = EmailNotificationModel().render_email(
|
||||
email_type, **kwargs)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue