GithubHelp home page GithubHelp logo

kinto-emailer's Introduction

kinto-emailer's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

kinto-emailer's Issues

Support batch requests

The current implementation is wrong. If serveral collecions or several records are impacted by a batch request, only one email is sent.

For example, it uses payload['collection_id'] instead of iterating on impacted_records.

Related: Kinto/kinto#945

Emails are not sent :|

Because we plug sending notifications to AfterResourceChanged, we are out of the request transaction.

Because we use get_mailer().send(), and because pyramid-tm is enabled, pyramid-emailer is waiting for the transaction to be committed to send emails.

The solution would be to use send_immediately(...) instead of send(). Or call transaction.commit() but this could have side effects so I would suggest the former.

Support template replacements from data.

  // Another example.
  {
    "kinto-emailer": {
      "sender": "Form Builder <[email protected]>",
      "collection.created": {
        "template": "You've just created a new form. Here are the details: \n- {email.data.formURL}\n -{email.data.formAdminURL}"
        "recipients": ['{email.recipients}']
      },

      "record.created": {
        "template": ""
        "recipients": ['{email.recipients}']
      }
    }
  }

/buckets/{buck}/collections/{collection}/emails contains recipients, can be accessed only by people with the write permission on the collection.

transaction/config issue ?

Hi, i'm trying to setup kinto-emailer for new records notifications. I've added it to KINTO_INCLUDES and created MAIL_DEFAULT_SENDER and MAIL_HOST as environment variables, but as soon as some notification is triggered i get this error message :

Unable to notify
Traceback (most recent call last):
  File "/app/kinto/core/events.py", line 181, in _notify_resource_events_after
    request.registry.notify(event)
  File "/usr/local/lib/python3.7/site-packages/pyramid/registry.py", line 109, in notify
    [_ for _ in self.subscribers(events, None)]
  File "/usr/local/lib/python3.7/site-packages/zope/interface/registry.py", line 448, in subscribers
    return self.adapters.subscribers(objects, provided)
  File "/usr/local/lib/python3.7/site-packages/zope/interface/adapter.py", line 619, in subscribers
    subscription(*objects)
  File "/usr/local/lib/python3.7/site-packages/pyramid/config/adapters.py", line 129, in subscriber_wrapper
    return derived_subscriber(*arg)
  File "/usr/local/lib/python3.7/site-packages/pyramid/config/adapters.py", line 101, in derived_subscriber
    return subscriber(arg[0])
  File "/usr/local/lib/python3.7/site-packages/kinto_emailer/__init__.py", line 58, in send_notification
    messages += get_messages(storage, _context)
  File "/usr/local/lib/python3.7/site-packages/kinto_emailer/__init__.py", line 118, in get_messages
    hooks = _get_emailer_hooks(storage, context)
  File "/usr/local/lib/python3.7/site-packages/kinto_emailer/__init__.py", line 78, in _get_emailer_hooks
    object_id=collection_id)
  File "/app/kinto/core/decorators.py", line 70, in wrapper
    return func(*args, **new_kwargs)
  File "/app/kinto/core/storage/postgresql/__init__.py", line 339, in get
    result = conn.execute(query, placeholders)
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 1291, in execute
    return self._connection_for_bind(bind, close_with_result=True).execute(
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 1147, in _connection_for_bind
    engine, execution_options
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/orm/session.py", line 458, in _connection_for_bind
    self.session.dispatch.after_begin(self.session, self, conn)
  File "/usr/local/lib/python3.7/site-packages/sqlalchemy/event/attr.py", line 261, in __call__
    fn(*args, **kw)
  File "/usr/local/lib/python3.7/site-packages/zope/sqlalchemy/datamanager.py", line 269, in after_begin
    session, self.initial_state, self.transaction_manager, self.keep_session
  File "/usr/local/lib/python3.7/site-packages/zope/sqlalchemy/datamanager.py", line 234, in join_transaction
    session, initial_state, transaction_manager, keep_session=keep_session
  File "/usr/local/lib/python3.7/site-packages/zope/sqlalchemy/datamanager.py", line 89, in __init__
    transaction_manager.get().join(self)
  File "/usr/local/lib/python3.7/site-packages/transaction/_transaction.py", line 191, in join
    Status.ACTIVE, Status.DOOMED, self.status))
ValueError: expected txn status 'Active' or 'Doomed', but it's 'Committed'

So looks like the notification is triggered but something is missing in my setup. Hard to tell what with this error though.

Any guidance on how to debug this ?

Switch config from dict to list

We may want to send two different emails for the same event. The current approach with the keys do not allow it.

I think also that we could use attributes to filter events, like this:

[
    {
        "resource_name": "record",
        "action": "create",
        "collection_id": "certificates",
        "template": "Hi, a new record '{uri}' has just been created in the collection '{bucket_id}/{collection_id}'",
        "recipients": ['Security reviewers <[email protected]>'],
        "sender": "Kinto team <[email protected]>"
    },
    {
        "event": "kinto_signer.events.ReviewRequested",
        "template": "Hi, a review is pending your approval on the collection '{bucket_id}/{collection_id}'",
        "recipients": ['Security reviewers <[email protected]>'],
        "sender": "Kinto team <[email protected]>"
    }
]

Crash on invalid template (e.g unknown payload keys)

  File "/home/mathieu/Code/Mozilla/kinto-emailer/.venv/local/lib/python2.7/site-packages/pyramid/config/adapters.py", line 103, in derived_subscriber
    return subscriber(arg[0])
  File "/home/mathieu/Code/Mozilla/kinto-emailer/kinto_emailer/__init__.py", line 24, in send_notification
    messages = get_messages(collection_record, payload)
  File "/home/mathieu/Code/Mozilla/kinto-emailer/kinto_emailer/__init__.py", line 53, in get_messages
    msg = hook['template'].format(**payload)
KeyError: u'userid' lang=None uid=5eba31d5d5a47ea957928b1d38bfdb6d394d711796de85410bc9fbef2b2cec8d

Idea: Define options using nested objects

{
  "kinto-emailer": {
    "sender": "Kinto team <[email protected]>"
    "record": {
      "recipients": ['Security reviewers <[email protected]>'],
      "create": {
        "template": "Hi, a new record '{uri}' has just been created in the collection '{bucket_id}/{collection_id}'",
      },
      "delete": {
        "template": "Hi, a record '{uri}' has just been deleted in the collection '{bucket_id}/{collection_id}'",
      }
    }
    "collection": {
      "recipients": ['Admins <[email protected]>'],
      "template": "Hi, a collection '{uri}' was {action}d.",
    }
  }
}

Support configuration on buckets

In our use case for blocklists, it would be better to be able to define the configuration on the staging bucket.

The groups URI could contain placeholder like this:
"/buckets/source/groups/{collection_id}-reviewers"

"hooks": [{
      "event": "kinto_signer.events.ReviewRequested",
      "subject": "{user_id} requested review on {bucket_id}/{collection_id}.",
      "template": "Review changes at {root_url}admin/#/buckets/{bucket_id}/collections/{collection_id}/records",
      "recipients": ["/buckets/source/groups/{collection_id}-reviewers"]
    }]

Pyramid email configuration via env variables

Hi, i've setup the plugin, and notifications are triggered correctly; Now i'm trying to configure MAIL_HOST and MAIL_DEFAULT_SENDER but looks like this is not configurable via env variables, only from the config file which is not ideal in my case.

While pyramid docs says one can use env vars to override configuration, i cant get it to work

Any idea where i should look to make this possible ?

kinto-emailer plugin tries to create debug directory even though no mail configuration is specified

This occurs with the kinto-dist docker image and with no mail configuration specified.

GMar 01 21:05:13 ip-172-31-23-160 docker[6965]: Setting up 'changes' listener
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: Traceback (most recent call last):
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: File "app.wsgi", line 23, in <module>
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: application = main(config.items('DEFAULT'), **dict(config.items('app:main')))
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: File "/usr/local/lib/python3.5/site-packages/kinto/__init__.py", line 52, in main
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: default_settings=DEFAULT_SETTINGS)
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: File "/usr/local/lib/python3.5/site-packages/kinto/core/initialization.py", line 586, in initialize
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: config.include("kinto.core", route_prefix=api_version)
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: File "/usr/local/lib/python3.5/site-packages/pyramid/config/__init__.py", line 800, in include
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: c(configurator)
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: File "/usr/local/lib/python3.5/site-packages/kinto/core/__init__.py", line 173, in includeme
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: config.include(app)
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: File "/usr/local/lib/python3.5/site-packages/pyramid/config/__init__.py", line 800, in include
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: c(configurator)
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: File "/usr/local/lib/python3.5/site-packages/kinto_emailer/__init__.py", line 179, in includeme
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: config.include('pyramid_mailer' + ('.debug' if debug else ''))
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: File "/usr/local/lib/python3.5/site-packages/pyramid/config/__init__.py", line 800, in include
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: c(configurator)
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: File "/usr/local/lib/python3.5/site-packages/pyramid_mailer/debug.py", line 8, in includeme
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: mailer = DebugMailer(path)
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: File "/usr/local/lib/python3.5/site-packages/pyramid_mailer/mailer.py", line 40, in __init__
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: makedirs(top_level_directory)
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: File "/usr/local/lib/python3.5/os.py", line 241, in makedirs
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: mkdir(name, mode)
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: PermissionError: [Errno 13] Permission denied: '/app/mail'
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: unable to load app 0 (mountpoint='') (callable not found or import error)
Mar 01 21:05:14 ip-172-31-23-160 docker[6965]: *** no app loaded. going in full dynamic mode ***

Crash with bucket_id KeyError

with a POST /v1/buckets

  File "/usr/local/lib/python3.5/site-packages/zope/interface/registry.py", line 442, in subscribers
    return self.adapters.subscribers(objects, provided)
  File "/usr/local/lib/python3.5/site-packages/zope/interface/adapter.py", line 598, in subscribers
    subscription(*objects)
  File "/usr/local/lib/python3.5/site-packages/pyramid/config/adapters.py", line 130, in subscriber_wrapper
    return derived_subscriber(*arg)
  File "/usr/local/lib/python3.5/site-packages/pyramid/config/adapters.py", line 103, in derived_subscriber
    return subscriber(arg[0])
  File "/usr/local/lib/python3.5/site-packages/kinto_emailer/__init__.py", line 140, in _validate_emailer_settings
    bucket_uri = '/buckets/{bucket_id}'.format(**event.payload)
    KeyError: 'bucket_id'","agent":"HTTPie/0.9.9","collection_id":"bucket","authn_type":"ldap","path":"/v1/buckets","errno":110},"Pid":8,"Timestamp":1498670780707000000,"EnvVersion":"2.0"}

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.