allura-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From tvansteenbu...@apache.org
Subject [2/6] git commit: [#6694] ticket:461 Form to send message to a user
Date Fri, 08 Nov 2013 04:45:47 GMT
[#6694] ticket:461 Form to send message to a user


Project: http://git-wip-us.apache.org/repos/asf/incubator-allura/repo
Commit: http://git-wip-us.apache.org/repos/asf/incubator-allura/commit/6ee08822
Tree: http://git-wip-us.apache.org/repos/asf/incubator-allura/tree/6ee08822
Diff: http://git-wip-us.apache.org/repos/asf/incubator-allura/diff/6ee08822

Branch: refs/heads/master
Commit: 6ee088220483d5f7a8d216fed7dfd5f475271c93
Parents: 38d7d8d
Author: Yuriy Arhipov <yuriyarhipovua@yandex.ru>
Authored: Fri Nov 1 13:35:41 2013 +0400
Committer: Tim Van Steenburgh <tvansteenburgh@gmail.com>
Committed: Fri Nov 8 04:30:15 2013 +0000

----------------------------------------------------------------------
 .../user_profile/templates/send_message.html    | 69 ++++++++++++++++++++
 .../ext/user_profile/templates/user_index.html  |  4 +-
 Allura/allura/ext/user_profile/user_main.py     | 45 ++++++++++++-
 Allura/allura/lib/mail_util.py                  |  4 +-
 Allura/allura/model/auth.py                     | 23 +++++++
 Allura/allura/tasks/mail_tasks.py               |  5 +-
 .../tests/functional/test_user_profile.py       | 45 +++++++++++++
 Allura/allura/tests/model/test_auth.py          | 13 ++++
 Allura/development.ini                          |  3 +
 Allura/test.ini                                 |  3 +
 10 files changed, 209 insertions(+), 5 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6ee08822/Allura/allura/ext/user_profile/templates/send_message.html
----------------------------------------------------------------------
diff --git a/Allura/allura/ext/user_profile/templates/send_message.html b/Allura/allura/ext/user_profile/templates/send_message.html
new file mode 100644
index 0000000..4dcec2d
--- /dev/null
+++ b/Allura/allura/ext/user_profile/templates/send_message.html
@@ -0,0 +1,69 @@
+{#-
+       Licensed to the Apache Software Foundation (ASF) under one
+       or more contributor license agreements.  See the NOTICE file
+       distributed with this work for additional information
+       regarding copyright ownership.  The ASF licenses this file
+       to you under the Apache License, Version 2.0 (the
+       "License"); you may not use this file except in compliance
+       with the License.  You may obtain a copy of the License at
+
+         http://www.apache.org/licenses/LICENSE-2.0
+
+       Unless required by applicable law or agreed to in writing,
+       software distributed under the License is distributed on an
+       "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+       KIND, either express or implied.  See the License for the
+       specific language governing permissions and limitations
+       under the License.
+-#}
+{% set hide_left_bar = True %}
+{% extends g.theme.master %}
+
+{% block title %}{{user.display_name}} / Profile{% endblock %}
+
+{% block header %}Send a Message{% endblock %}
+
+{% block head %}
+  <link rel="alternate" type="application/rss+xml" title="RSS" href="feed.rss">
+  <link rel="alternate" type="application/atom+xml" title="Atom" href="feed.atom">
+{% endblock %}
+{% block actions %}
+  <a href="{{c.app.url}}feed.rss" title="Follow"><b data-icon="{{g.icons['feed'].char}}"
class="ico {{g.icons['feed'].css}}"></b></a>
+{% endblock %}
+
+{% block content %}
+    {%if not expire_time%}
+    <div class="grid-24">
+        <div class="grid-24">
+            <b>To:</b> <a href="{{user.url()}}">{{user.display_name|default(user.username)}}</a>
+        </div>
+        <div class="grid-24">
+            <b>From:</b> {{c.user.email_address_header()}}
+        </div>
+        <div class="clear">&nbsp;</div>
+        <form action="send_user_message" method="post">
+            <div class="grid-24">
+                <label for="subject"><b>Subject:</b></label>
+            </div>
+            <input class="grid-10" type="text" name="subject" id="subject">
+            <div class="grid-24">&nbsp;</div>
+            <div class="grid-24">
+                <label for="message"><b>Message:</b></label>
+            </div>
+            <textarea class="grid-10" name="message" id="message" style="height:100px;"></textarea>
+            <div class="grid-24">
+                <input type="checkbox" name="cc" id="ccsender">
+                <label for="ccsender">CC Sender</label>
+            </div>
+            <div class="grid-24">&nbsp;</div>
+            <div class="grid-24">
+                <input type="submit" value="Send Message">
+            </div>
+        </form>
+    </div>
+    {% else %}
+    <div class="grid-24">
+        <h2>Sorry, you can send an email after {{expire_time}}</h2>
+    </div>
+    {% endif %}
+{% endblock %}

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6ee08822/Allura/allura/ext/user_profile/templates/user_index.html
----------------------------------------------------------------------
diff --git a/Allura/allura/ext/user_profile/templates/user_index.html b/Allura/allura/ext/user_profile/templates/user_index.html
index 54cae11..f328085 100644
--- a/Allura/allura/ext/user_profile/templates/user_index.html
+++ b/Allura/allura/ext/user_profile/templates/user_index.html
@@ -228,7 +228,9 @@
         </div>
       </div>
     {% endif %}
-
+ <div class="grid-24">
+    <b><a href="send_message">Send me a message</a></b>
+ </div>
   </div><!-- end of Personal data section -->
   <div class="grid-24">
     <b>Current {{user.get_pref('display_name')}}'s skills list</b>

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6ee08822/Allura/allura/ext/user_profile/user_main.py
----------------------------------------------------------------------
diff --git a/Allura/allura/ext/user_profile/user_main.py b/Allura/allura/ext/user_profile/user_main.py
index 09e436c..b4b76ab 100644
--- a/Allura/allura/ext/user_profile/user_main.py
+++ b/Allura/allura/ext/user_profile/user_main.py
@@ -22,8 +22,9 @@ import pkg_resources
 from pylons import tmpl_context as c, app_globals as g
 from pylons import request
 from formencode import validators
-from tg import expose, redirect, validate, response
+from tg import expose, redirect, validate, response, config, flash
 from webob import exc
+from datetime import timedelta, datetime
 
 from allura import version
 from allura.app import Application, SitemapEntry
@@ -106,3 +107,45 @@ class UserProfileController(BaseController, FeedController):
             {'author_link': user.url()},
             'Recent posts by %s' % user.display_name,
             project.url())
+
+    @expose('jinja:allura.ext.user_profile:templates/send_message.html')
+    def send_message(self, subject='', message='', cc=None, errors=None):
+        user = c.project.user_project_of
+        if not user:
+            raise exc.HTTPNotFound()
+
+        time_interval = config['user_message.time_interval']
+        max_messages = config['user_message.max_messages']
+        expire_time = None
+
+        if not c.user.check_send_emails_times(time_interval, max_messages):
+            expire_seconds = c.user.send_emails_times[0] + timedelta(seconds=int(time_interval))
- datetime.utcnow()
+            h, remainder = divmod(expire_seconds.total_seconds(), 3600)
+            m, s = divmod(remainder, 60)
+            expire_time = '%s:%s:%s' % (int(h), int(m), int(s))
+
+        return dict(user=user, expire_time=expire_time)
+
+    @require_post()
+    @expose()
+    @validate(dict(subject=validators.NotEmpty,
+                   message=validators.NotEmpty))
+    def send_user_message(self, subject='', message='', cc=None):
+
+        if c.form_errors:
+            error_msg = ''
+            for field, error in c.form_errors.iteritems():
+                error_msg += '%s: %s ' % (field, error)
+            flash(error_msg, 'error')
+            redirect(request.referer)
+        time_interval = config['user_message.time_interval']
+        max_messages = config['user_message.max_messages']
+        if cc:
+            cc = c.user.get_pref('email_address')
+        user = c.project.user_project_of
+        if c.user.check_send_emails_times(time_interval, max_messages):
+            c.user.send_user_message(user, subject, message, cc)
+        else:
+            flash("You can't send more than %s messages per %s seconds" % (max_messages,
time_interval), 'error')
+        return redirect(user.url())
+

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6ee08822/Allura/allura/lib/mail_util.py
----------------------------------------------------------------------
diff --git a/Allura/allura/lib/mail_util.py b/Allura/allura/lib/mail_util.py
index b3e3b11..b376c3d 100644
--- a/Allura/allura/lib/mail_util.py
+++ b/Allura/allura/lib/mail_util.py
@@ -202,7 +202,7 @@ class SMTPClient(object):
         self._client = None
 
     def sendmail(self, addrs, fromaddr, reply_to, subject, message_id, in_reply_to, message,
-                 sender=None, references=None):
+                 sender=None, references=None, cc=None):
         if not addrs: return
         # We send one message with multiple envelope recipients, so use a generic To: addr
         # It might be nice to refactor to send one message per recipient, and use the actual
To: addr
@@ -213,6 +213,8 @@ class SMTPClient(object):
         message['Message-ID'] = Header('<' + message_id + u'>')
         if sender:
             message['Sender'] = AddrHeader(sender)
+        if cc:
+            message['CC'] = AddrHeader(cc)
         if in_reply_to:
             if not isinstance(in_reply_to, basestring):
                 raise TypeError('Only strings are supported now, not lists')

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6ee08822/Allura/allura/model/auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/model/auth.py b/Allura/allura/model/auth.py
index 2bc0ba3..63da96e 100644
--- a/Allura/allura/model/auth.py
+++ b/Allura/allura/model/auth.py
@@ -33,6 +33,7 @@ import iso8601
 import pymongo
 from pylons import tmpl_context as c, app_globals as g
 from pylons import request
+from tg import flash
 
 from ming import schema as S
 from ming import Field, collection
@@ -333,6 +334,7 @@ class User(MappedClass, ActivityNode, ActivityObject):
         end_time=dict(h=int, m=int))])
     localization=FieldProperty(dict(city=str,country=str))
     timezone=FieldProperty(str)
+    send_emails_times=FieldProperty([S.DateTime])
     inactiveperiod=FieldProperty([dict(
         start_date=S.DateTime,
         end_date=S.DateTime)])
@@ -352,6 +354,27 @@ class User(MappedClass, ActivityNode, ActivityObject):
     #Statistics
     stats_id = FieldProperty(S.ObjectId, if_missing=None)
 
+    def check_send_emails_times(self, time_interval, max_messages):
+        times = []
+        time_interval = timedelta(seconds=int(time_interval))
+        for t in self.send_emails_times:
+            if t + time_interval > datetime.utcnow():
+                times.append(t)
+        self.send_emails_times = times
+        return len(times) < int(max_messages)
+
+    def send_user_message(self, user, subject, message, cc):
+        allura.tasks.mail_tasks.sendsimplemail.post(
+            toaddr=user.get_pref('email_address'),
+            fromaddr=c.user.get_pref('email_address'),
+            reply_to=c.user.get_pref('email_address'),
+            message_id=h.gen_message_id(),
+            subject=subject,
+            text=message,
+            cc=cc)
+        self.send_emails_times.append(datetime.utcnow())
+        flash("email sent")
+
     @property
     def activity_name(self):
         return self.display_name or self.username

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6ee08822/Allura/allura/tasks/mail_tasks.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tasks/mail_tasks.py b/Allura/allura/tasks/mail_tasks.py
index 9b7fbd5..8151d34 100644
--- a/Allura/allura/tasks/mail_tasks.py
+++ b/Allura/allura/tasks/mail_tasks.py
@@ -147,7 +147,8 @@ def sendsimplemail(
     message_id,
     in_reply_to=None,
     sender=None,
-    references=None):
+    references=None,
+    cc=None):
     from allura import model as M
     if fromaddr is None:
         fromaddr = u'noreply@in.sf.net'
@@ -166,4 +167,4 @@ def sendsimplemail(
     multi_msg = mail_util.make_multipart_message(plain_msg, html_msg)
     smtp_client.sendmail(
         [toaddr], fromaddr, reply_to, subject, message_id,
-        in_reply_to, multi_msg, sender=sender, references=references)
+        in_reply_to, multi_msg, sender=sender, references=references, cc=cc)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6ee08822/Allura/allura/tests/functional/test_user_profile.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/functional/test_user_profile.py b/Allura/allura/tests/functional/test_user_profile.py
index e5a9aef..6730d6e 100644
--- a/Allura/allura/tests/functional/test_user_profile.py
+++ b/Allura/allura/tests/functional/test_user_profile.py
@@ -17,6 +17,8 @@
 
 from formencode.variabledecode import variable_encode
 
+import mock
+
 from allura.model import Project, User
 from allura.tests import decorators as td
 from allura.tests import TestController
@@ -57,3 +59,46 @@ class TestUserProfile(TestController):
             r = self.app.get('/u/test-admin/profile/feed%s' % ext, status=200)
             assert 'Recent posts by Test Admin' in r
             assert 'Home modified by Test Admin' in r
+
+    @td.with_user_project('test-admin')
+    @td.with_user_project('test-user')
+    @mock.patch('allura.tasks.mail_tasks.sendsimplemail')
+    @mock.patch('allura.lib.helpers.gen_message_id')
+    @mock.patch('allura.model.User.check_send_emails_times')
+    def test_send_message(self, check, gen_message_id, sendsimplemail):
+        check.return_value = True
+        gen_message_id.return_value = 'id'
+        response = self.app.get('/u/test-user/profile/send_message', status=200)
+        assert '<b>From:</b> &#34;Test Admin&#34; &lt;test-admin@users.localhost&gt;'
in response
+        self.app.post('/u/test-user/profile/send_user_message',
+                      params={'subject': 'test subject',
+                              'message': 'test message',
+                              'cc': 'on'})
+
+        sendsimplemail.post.assert_called_once_with(
+            cc=User.by_username('test-admin').get_pref('email_address'),
+            text=u'test message',
+            toaddr=User.by_username('test-user').get_pref('email_address'),
+            fromaddr=User.by_username('test-admin').get_pref('email_address'),
+            reply_to=User.by_username('test-admin').get_pref('email_address'),
+            message_id=u'id',
+            subject=u'test subject')
+        sendsimplemail.reset_mock()
+        self.app.post('/u/test-user/profile/send_user_message',
+                      params={'subject': 'test subject',
+                              'message': 'test message'})
+
+        sendsimplemail.post.assert_called_once_with(
+            cc=None,
+            text=u'test message',
+            toaddr=User.by_username('test-user').get_pref('email_address'),
+            fromaddr=User.by_username('test-admin').get_pref('email_address'),
+            reply_to=User.by_username('test-admin').get_pref('email_address'),
+            message_id=u'id',
+            subject=u'test subject')
+
+        check.return_value = False
+        response = self.app.get('/u/test-user/profile/send_message', status=200)
+        assert 'Sorry, you can send an email after' in response
+
+

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6ee08822/Allura/allura/tests/model/test_auth.py
----------------------------------------------------------------------
diff --git a/Allura/allura/tests/model/test_auth.py b/Allura/allura/tests/model/test_auth.py
index f8e7ed8..db57c18 100644
--- a/Allura/allura/tests/model/test_auth.py
+++ b/Allura/allura/tests/model/test_auth.py
@@ -24,6 +24,7 @@ from nose.tools import with_setup, assert_equal
 from pylons import tmpl_context as c, app_globals as g
 from webob import Request
 from mock import patch
+from datetime import datetime, timedelta
 
 from pymongo.errors import DuplicateKeyError
 from ming.orm.ormsession import ThreadLocalORMSession
@@ -32,6 +33,7 @@ from allura import model as M
 from allura.lib import plugin
 from allura.tests import decorators as td
 from alluratest.controller import setup_basic_test, setup_global_objects
+from allura.tasks import mail_tasks
 
 
 def setUp():
@@ -225,3 +227,14 @@ def test_user_projects_by_role():
     g.credentials.clear()
     assert_equal(set(p.shortname for p in c.user.my_projects()), set(['test', 'test2', 'u/test-admin',
'adobe-1', '--init--']))
     assert_equal(set(p.shortname for p in c.user.my_projects('Admin')), set(['test', 'u/test-admin',
'adobe-1', '--init--']))
+
+
+def test_check_send_emails_times():
+    user1 = M.User.register(dict(username='test-user'), make_project=False)
+    time1 = datetime.utcnow() - timedelta(minutes=30)
+    time2 = datetime.utcnow() - timedelta(minutes=45)
+    time3 = datetime.utcnow() - timedelta(minutes=70)
+    user1.send_emails_times = [time1, time2, time3]
+    assert not user1.check_send_emails_times(3600, 1)
+    assert_equal(len(user1.send_emails_times), 2)
+    assert user1.check_send_emails_times(3600, 3)

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6ee08822/Allura/development.ini
----------------------------------------------------------------------
diff --git a/Allura/development.ini b/Allura/development.ini
index 4a96528..2c701cb 100644
--- a/Allura/development.ini
+++ b/Allura/development.ini
@@ -272,6 +272,9 @@ forgeblog.exfeed = false
 
 short_url.url_pattern = {base_url}/{nbhd}/{project}/{mount_point}/{short_name}
 
+user_message.time_interval = 3600
+user_message.max_messages = 20
+
 [app:tool_test]
 use = egg:Allura
 override_root=basetest_project_root

http://git-wip-us.apache.org/repos/asf/incubator-allura/blob/6ee08822/Allura/test.ini
----------------------------------------------------------------------
diff --git a/Allura/test.ini b/Allura/test.ini
index 1931a92..8747433 100644
--- a/Allura/test.ini
+++ b/Allura/test.ini
@@ -121,6 +121,9 @@ short_url.url_pattern = {base_url}/{nbhd}/{project}/{mount_point}/{short_name}
 # tests expect max length of 40000
 markdown_render_max_length = 40000
 
+user_message.time_interval = 3600
+user_message.max_messages = 200
+
 [app:main_without_authn]
 use = main
 skip_authentication = True


Mime
View raw message