Send sharing notifications.
authorSofia Papagiannaki <papagian@gmail.com>
Tue, 10 Apr 2012 09:15:40 +0000 (12:15 +0300)
committerSofia Papagiannaki <papagian@gmail.com>
Tue, 10 Apr 2012 09:15:40 +0000 (12:15 +0300)
Fixes #2295

snf-pithos-app/README
snf-pithos-app/pithos/api/dispatch.py
snf-pithos-backend/pithos/backends/lib/sqlalchemy/permissions.py
snf-pithos-backend/pithos/backends/lib/sqlite/permissions.py
snf-pithos-backend/pithos/backends/modular.py

index 42d3a50..3f6bbd0 100644 (file)
@@ -47,6 +47,10 @@ To update checksums asynchronously, enable the queue, install snf-pithos-tools a
 
     pithos-dispatcher --exchange=pithos --key=pithos.object --callback=pithos.api.dispatch.update_md5
 
+To send sharing notifications::
+
+    pithos-dispatcher --exchange=pithos --key=pithos.sharing --callback=pithos.api.dispatch.send_sharing_notification
+
 Administrator functions
 -----------------------
 
index 09761da..d4c2561 100644 (file)
@@ -5,6 +5,11 @@ from pithos.api.settings import (BACKEND_DB_MODULE, BACKEND_DB_CONNECTION,
 from pithos.backends import connect_backend
 from pithos.api.util import hashmap_md5
 
+from django.core.mail import send_mail
+from django.utils.translation import ugettext as _
+
+from astakos.im.settings import DEFAULT_FROM_EMAIL
+
 def update_md5(m):
     if m['resource'] != 'object' or m['details']['action'] != 'object update':
         return
@@ -33,3 +38,22 @@ def update_md5(m):
         print 'WARNING: Can not update checksum for path "%s" (%s)' % (path, e)
     
     backend.close()
+
+def send_sharing_notification(m):
+    if m['resource'] != 'sharing':
+        return
+    
+    members = m['details']['members']
+    user = m['details']['user']
+    path = m['value']
+    account, container, name = path.split('/', 2)
+    
+    subject = 'Invitation to a Pithos+ shared object'
+    from_email = DEFAULT_FROM_EMAIL
+    recipient_list = members
+    message = 'User %s has invited you to a Pithos+ shared object. You can view it under "Shared to me" at "%s".' %(user, path)
+    try:
+        send_mail(subject, message, from_email, recipient_list)
+        print 'INFO: Sharing notification sent for path "%s" to %s' % (path, ','.join(recipient_list))
+    except (SMTPException, socket.error) as e:
+        print 'WARNING: Can not update send email for sharing "%s" (%s)' % (path, e)
index 2e03c95..af902f8 100644 (file)
@@ -92,6 +92,23 @@ class Permissions(XFeatures, Groups, Public):
             del(permissions[WRITE])
         return permissions
     
+    def access_members(self, path):
+        feature = self.xfeature_get(path)
+        if not feature:
+            return []
+        permissions = self.feature_dict(feature)
+        members = set()
+        members.update(permissions.get(READ, []))
+        members.update(permissions.get(WRITE, []))
+        for m in set(members):
+            parts = m.split(':', 1)
+            if len(parts) != 2:
+                continue
+            user, group = parts
+            members.remove(m)
+            members.update(self.group_members(user, group))
+        return list(members)
+    
     def access_clear(self, path):
         """Revoke access to path (both permissions and public)."""
         
index 476aaf2..6d5d13c 100644 (file)
@@ -89,6 +89,23 @@ class Permissions(XFeatures, Groups, Public):
             del(permissions[WRITE])
         return permissions
     
+    def access_members(self, path):
+        feature = self.xfeature_get(path)
+        if not feature:
+            return []
+        permissions = self.feature_dict(feature)
+        members = set()
+        members.update(permissions.get(READ, []))
+        members.update(permissions.get(WRITE, []))
+        for m in set(members):
+            parts = m.split(':', 1)
+            if len(parts) != 2:
+                continue
+            user, group = parts
+            members.remove(m)
+            members.update(self.group_members(user, group))
+        return members
+    
     def access_clear(self, path):
         """Revoke access to path (both permissions and public)."""
         
index 0dfd580..1153f23 100644 (file)
@@ -104,9 +104,9 @@ def backend_method(func=None, autocommit=1):
         try:
             self.messages = []
             ret = func(self, *args, **kw)
-            self.wrapper.commit()
             for m in self.messages:
                 self.queue.send(*m)
+            self.wrapper.commit()
             return ret
         except:
             self.wrapper.rollback()
@@ -603,6 +603,7 @@ class ModularBackend(BaseBackend):
         path = self._lookup_object(account, container, name)[0]
         self._check_permissions(path, permissions)
         self.permissions.access_set(path, permissions)
+        self._report_sharing_change(user, account, path, {'members':self.permissions.access_members(path)})
     
     @backend_method
     def get_object_public(self, user, account, container, name):
@@ -671,6 +672,7 @@ class ModularBackend(BaseBackend):
         
         if permissions is not None:
             self.permissions.access_set(path, permissions)
+            self._report_sharing_change(user, account, path, {'members':self.permissions.access_members(path)})
         
         self._report_object_change(user, account, path, details={'version': dest_version_id, 'action': 'object update'})
         return dest_version_id
@@ -1018,6 +1020,11 @@ class ModularBackend(BaseBackend):
         details.update({'user': user})
         self.messages.append((QUEUE_MESSAGE_KEY_PREFIX % ('object',), account, QUEUE_INSTANCE_ID, 'object', path, details))
     
+    def _report_sharing_change(self, user, account, path, details={}):
+        logger.debug("_report_permissions_change: %s %s %s %s", user, account, path, details)
+        details.update({'user': user})
+        self.messages.append((QUEUE_MESSAGE_KEY_PREFIX % ('sharing',), account, QUEUE_INSTANCE_ID, 'sharing', path, details))
+    
     # Policy functions.
     
     def _check_policy(self, policy):