summaryrefslogtreecommitdiff
path: root/python-nuntius.spec
diff options
context:
space:
mode:
authorCoprDistGit <infra@openeuler.org>2023-05-18 06:42:40 +0000
committerCoprDistGit <infra@openeuler.org>2023-05-18 06:42:40 +0000
commitf41f0f29b22be72b2e2d63c065f954db85777853 (patch)
treea8ba6266c4a4349e8dece03021872015ea5c9493 /python-nuntius.spec
parenta8b6c2b944dbed403639a5d58669b026d3e7bcba (diff)
automatic import of python-nuntius
Diffstat (limited to 'python-nuntius.spec')
-rw-r--r--python-nuntius.spec1014
1 files changed, 1014 insertions, 0 deletions
diff --git a/python-nuntius.spec b/python-nuntius.spec
new file mode 100644
index 0000000..760cbe9
--- /dev/null
+++ b/python-nuntius.spec
@@ -0,0 +1,1014 @@
+%global _empty_manifest_terminate_build 0
+Name: python-nuntius
+Version: 2.3.2
+Release: 1
+Summary: A newsletter app to be used with Django or standalone.
+License: GPLv3
+URL: https://github.com/lafranceinsoumise/nuntius
+Source0: https://mirrors.nju.edu.cn/pypi/web/packages/0e/d5/afc0a4ba5a690cea25e84e8b6af582256b8afe0d0ac7d342c0f6f635718e/nuntius-2.3.2.tar.gz
+BuildArch: noarch
+
+Requires: python3-Django
+Requires: python3-Pillow
+Requires: python3-django-stdimage
+Requires: python3-html2text
+Requires: python3-tenacity
+Requires: python3-django-anymail
+Requires: python3-boto3
+Requires: python3-mysqlclient
+Requires: python3-django-push-notifications
+Requires: python3-apns
+Requires: python3-pywebpush
+Requires: python3-dj-database-url
+
+%description
+# Nuntius
+
+Nuntius is a newsletter / push notification campaign application for Django.
+
+Nuntius integrates with your Django project.
+It is very agnostic about your subscribers and subscriber lists models.
+
+It features [Mosaico](https://mosaico.io/), a drag-and-drop email
+editor, for sending beautiful emails to your subscribers and
+push notification support through Apple Push Notification service (APNs)
+and Google Cloud Messaging (GCM).
+
+## How it works
+
+Nuntius is agnostic about your subscribers model. You can use your current
+use model, as long as it implements a few required methods.
+
+To allow your end-users to choose recipients, it is your choice to implement
+one or more "segment" models. Segment models implement a required method
+`get_subscribers_queryset`.
+
+You can then create campaigns in the Django admin panel, and send them to
+existing segments.
+
+## Installation
+
+1. Add "push_notifications" and "nuntius" to your INSTALLED_APPS setting like this:
+ ````python
+ INSTALLED_APPS = [
+ 'django.contrib.admin',
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+ ...
+ 'push_notifications',
+ 'nuntius',
+ ]
+ ````
+2. Include Nuntius urlconf in your project `urls.py` like this:
+ ````python
+ path('nuntius/', include('nuntius.urls')),
+ ````
+3. Define your subscriber model so it works with Nuntius.
+ You must inherit from
+ [`nuntius.models.AbstractSubscriber`](https://github.com/lafranceinsoumise/nuntius/blob/master/nuntius/models.py#L174)
+ and implement all the necessary methods. An easy way to do this is to use directly or to extend
+ [`BaseSubscriber`](https://github.com/lafranceinsoumise/nuntius/blob/master/nuntius/models.py#L204), but
+ you can implement the methods of `AbstractSubscriber` the way you want.
+
+ Here are the methods you must implement :
+
+ * `get_subscriber_status()`
+ must return one of `AbstractSubscriber.STATUS_CHOICES`. You can also simply
+ define a `subscriber_status` attribute.
+
+ * `get_subscriber_email()`
+ must return a unique email address for the subscriber. You can also simply
+ define an `email` attribute.
+
+ * `get_subscriber_data()`
+ must return the dictionnary of values which can be used as substitution in
+ the emails. Default is `{"email": self.get_subscriber_email()}`.
+
+ * `get_subscriber_push_devices()` (optional)
+ must return a list of `django-push-notifications.APNSDevice`
+ and `django-push-notifications.GCMDevice` model instances
+ (cf. [the `django-push-notifications` documentation](https://github.com/jazzband/django-push-notifications))
+
+
+
+4. Tell Nuntius how to find your subscriber model in `settings.py`
+ ````python
+ NUNTIUS_SUBSCRIBER_MODEL = 'myapp.MySubscriberModel'
+ ````
+
+5. Launch the nuntius worker in the background. In a production setting, this should be done through
+ a process monitor like upstart or systemd.
+ ```shell script
+ export DJANGO_SETTINGS_MODULE=myapp.settings
+ python ./manage.py nuntius_worker
+ ```
+
+6. Unless you are using a custom admin site, admin panels for Nuntius will be
+[autodiscovered](https://docs.djangoproject.com/en/2.0/ref/contrib/admin/#discovery-of-admin-files)
+and added to you admin site. If you use a custom admin site, you need to register
+Nuntius models with something like:
+
+ ```python
+ admin_site.register(nuntius.models.Campaign, nuntius.admin.CampaignAdmin)
+ admin_site.register(nuntius.models.CampaignSentEvent, nuntius.admin.CampaignSentEventAdmin)
+ ```
+
+## Other settings
+Use `NUNTIUS_DEFAULT_FROM_EMAIL`, `NUNTIUS_DEFAULT_FROM_NAME`, `NUNTIUS_DEFAULT_REPLY_TO_EMAIL`,
+`NUNTIUS_DEFAULT_REPLY_TO_NAME` to change default field values in the admin form.
+
+Use `NUNTIUS_ENABLED_CAMPAIGN_TYPES` to choose which types of campaign
+you want to enable by default (`email` *default*, `push` or `email,push`)
+
+In order to use push notifications, `NUNTIUS_PUSH_NOTIFICATION_SETTINGS` must be specified
+(cf. [the `django-push-notifications` documentation](https://github.com/jazzband/django-push-notifications#settings-list))
+```py
+NUNTIUS_PUSH_NOTIFICATIONS_SETTINGS = {
+ "FCM_API_KEY": "[your api key]",
+ "GCM_API_KEY": "[your api key]",
+ "APNS_CERTIFICATE": "/path/to/your/certificate.pem",
+ "APNS_TOPIC": "com.example.push_test",
+ # ...
+}
+```
+
+## Advanced usage
+
+### List segments
+
+If you want to have more control on your recipients, you can create a
+segment model.
+
+One example of segment is a simple model which holds a Many-to-Many relation
+to subscribers.
+
+Another example is a segment model which filters subscribers depending on
+the date of their last login :
+
+```python
+from django.db import models
+from django.db.models import fields
+from datetime import datetime
+
+from nuntius.models import BaseSegment
+
+
+class LastLoginDateSegment(BaseSegment, models.Model):
+ last_login_duration = fields.DurationField()
+
+ def get_display_name(self):
+ return f'Last login : {str(datetime.now() - self.last_login_duration)}'
+
+ def get_subscribers_queryset(self):
+ return MySubscriberClass.objects.filter(last_login__gt=datetime.now() - self.last_login_duration)
+
+ def get_subscribers_count(self):
+ return MySubscriberClass.objects.filter(last_login__gt=datetime.now() - self.last_login_duration, subscribed=True)
+
+```
+
+* `get_subscribers_queryset` is allowed to return subscribers regardless of their
+ `subscriber_status`, as `get_subscriber_status` will be called on each instance.
+* `get_subscribers_count` is only there for convenience in the admin panel, it does not
+ have to be accurate. If you want to have it accurate, you should however take
+ your subscribers status into account.
+
+Then, add your segment model to Nuntius settings :
+````python
+NUNTIUS_SEGMENT_MODEL = 'myapp.lastlogindatesegment'
+````
+
+### Custom template
+
+You can write your own Mosaico template to fit your needs. To make it available in the admin,
+list the public URL path of the template in `NUNTIUS_MOSAICO_TEMPLATES`. The template can be served
+by Django static files system, or any other way at your preference.
+
+```python
+NUNTIUS_MOSAICO_TEMPLATES = [
+ ("/static/mosaico_templates/versafix-2/template-versafix-2.html", "Custom template")
+]
+```
+
+### Sending parameters
+
+The worker will spawn several subprocesses to speed up the sending of campaigns. The number of
+processes that will send emails concurrently can be configured using the `NUNTIUS_MAX_CONCURRENT_SENDERS`
+setting.
+
+Most ESP enforce a maximum send rate. Nuntius won't sent messages faster than`NUNTIUS_MAX_SENDING_RATE`,
+in messages per second.
+
+When using SMTP, some ESP limit the number of emails that can be sent using a single connection.
+`NUNTIUS_MAX_MESSAGES_PER_CONNECTION` will force Nuntius to reset the connection after sending that
+many messages.
+
+The Nuntius worker checks every `NUNTIUS_POLLING_INTERVAL` seconds if any sending has been scheduled
+or canceled. The default value of 2 seconds should be find for most usages.
+
+To help you configure these parameters, you can send SIGUSR1 to the main worker process and it will
+print sending statistics on `stderr`. Pay special attention to the current sending rate and to the
+current bucket capacity: if your sending rate is lower than the maximum you configured, it most
+likely means the value you chose for `NUNTIUS_MAX_CONCURRENT_SENDERS` is not high enough given
+the latency you're getting with your ESP.
+
+### ESP and Webhooks
+
+Maintaining your own SMTP server to send your newsletter is probably
+a bad idea if you have more than a few subscribers. You can use
+[Anymail](https://github.com/anymail/django-anymail) along with Nuntius
+in order to use an email service provider. Anymail supports
+a lot of ESP, like Amazon SES, Mailgun, Mailjet, Postmark, SendGrid,
+SendinBlue, or SparkPost.
+
+Refer to the steps in [Anymail 1-2-3](https://anymail.readthedocs.io/en/stable/quickstart/)
+to install Anymail. If you want to configure Anymail just for Nuntius and keep
+the default email backend for other usage, you can use the setting `NUNTIUS_EMAIL_BACKEND`
+rather than the default `EMAIL_BACKEND`.
+
+In addition, configuring Nuntius with Anymail will allow you to use ESP tracking features
+and to track status of your email once it is sent.
+
+#### Webhooks
+
+Configuring webhhoks allows Nuntius to track email status and to
+give you statistics on campaign, as well as updating subscriber status
+when they bounce.
+
+1. Configure email tracking as described in
+[Anymail documentation](https://anymail.readthedocs.io/en/stable/installation/#configuring-tracking-and-inbound-webhooks).
+2. Implement the method `set_subscriber_status(self, email, status)` on your subscriber
+model manager.
+
+Nuntius will automatically listen to Anymail signals and call this method if needed.
+
+##### Handling of non-nuntius events (optional)
+
+If you send emails to your subscribers by other means than Nuntius (for example,
+transactional emails), you will receive webhooks events which are not related to
+a campaign you sent. By default, Nuntius will create a campaign result event recording
+the email and the event type, but it will not link it to a campaign nor to a subscriber
+model.
+
+If you want your events to always be linked to a subscriber model, you must implement
+a `get_subscriber(self, email_address)` method on your subscriber model manager.
+
+
+##### BaseSubscriberManager
+
+Nuntius is packaged with a BaseSubscriberManager, which implements both
+`set_subscriber_status` and `get_subscriber`, assuming you have an `email` field
+on your subscriber model. This is the default manager used by `BaseSubscriber`.
+
+
+#### Bounce handling
+
+Most ESP gives you a reputation based on your hard bounce rate.
+Mosaico handles bounces smartly to change your subscribers status
+when necessary.
+
+If Nuntius receive a bounce event on an email address which has no
+other sending event, `set_subscriber_status(email, status)` is called
+with `AbstractSubscriber.STATUS_BOUNCED`.
+
+If a successful sending event exists for this address,
+three parameters are taken into account :
+* if during the last `duration` days, there has been no more bounces than `limit`
+and at least one successful sending, no action is taken
+* if there has been at least one successful sending in the last
+`consecutive` events, no action is taken
+* otherwise, `set_subscriber_status(email, status)` is called
+with `AbstractSubscriber.STATUS_BOUNCED`
+
+
+You can change thoses default values :
+```python
+NUNTIUS_BOUNCE_PARAMS = {
+ "consecutive": 1,
+ "duration": 7,
+ "limit": 3
+}
+```
+
+**Example :**
+
+* You send 3 campaigns a week. After a few months, a subscriber
+has a full mailbox. On first and second bounced campaign, no action
+is taken because there is a successful sending in the last 7 days,
+and no more than 3 bounces. On the third campaign, if the user has empty
+their mailbox, everything is fine. Otherwise, the subscriber is marked
+as permanently bounced.
+* You send one campaign a day. A user has a buggy email server.
+This week, the user has already 3 bounces. When you receive the 4th
+bounce, if there has been a successful sending just before,
+everything is fine. Otherwise, the subscriber is marked
+as permanently bounced.
+
+## Tracking
+
+Opening and clicks are tracked by adding a white pixel and replacing links in emails, and by using a proxy URL on
+push notification clicks.
+
+Nuntius also adds [UTM parameters](https://en.wikipedia.org/wiki/UTM_parameters) to every URL with the following values:
+* `utm_source`: *"nuntius"*
+* `utm_medium`: *"email"*
+* `utm_campaign`: value configured by user at the campaign level
+* `utm_content`: *"link-{number}"* based on the link position in the email
+* `utm_term`: attribute `utm_term` of the segment object, or empty string if attribute does not exist
+
+In some situations, two details may be important for you:
+
+1. `utm_campaign`, `utm_content`, and `utm_term`, those are just defaults values, and can also be set directly on
+the link. `utm_source` and `utm_medium` will always be overwritten.
+2. `utm_content` and `utm_term` are set at sending time and cannot change afterwards. `utm_campaign` is
+set at click time, during the redirection from nuntius tracking URL to target URL, so if you change the value
+at the campaign level after sending, the value will change for all new clicks.
+
+## License
+
+Copyright is owned by Jill Royer and Arthur Cheysson.
+
+You can use Nuntius under GPLv3 terms.
+
+
+%package -n python3-nuntius
+Summary: A newsletter app to be used with Django or standalone.
+Provides: python-nuntius
+BuildRequires: python3-devel
+BuildRequires: python3-setuptools
+BuildRequires: python3-pip
+%description -n python3-nuntius
+# Nuntius
+
+Nuntius is a newsletter / push notification campaign application for Django.
+
+Nuntius integrates with your Django project.
+It is very agnostic about your subscribers and subscriber lists models.
+
+It features [Mosaico](https://mosaico.io/), a drag-and-drop email
+editor, for sending beautiful emails to your subscribers and
+push notification support through Apple Push Notification service (APNs)
+and Google Cloud Messaging (GCM).
+
+## How it works
+
+Nuntius is agnostic about your subscribers model. You can use your current
+use model, as long as it implements a few required methods.
+
+To allow your end-users to choose recipients, it is your choice to implement
+one or more "segment" models. Segment models implement a required method
+`get_subscribers_queryset`.
+
+You can then create campaigns in the Django admin panel, and send them to
+existing segments.
+
+## Installation
+
+1. Add "push_notifications" and "nuntius" to your INSTALLED_APPS setting like this:
+ ````python
+ INSTALLED_APPS = [
+ 'django.contrib.admin',
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+ ...
+ 'push_notifications',
+ 'nuntius',
+ ]
+ ````
+2. Include Nuntius urlconf in your project `urls.py` like this:
+ ````python
+ path('nuntius/', include('nuntius.urls')),
+ ````
+3. Define your subscriber model so it works with Nuntius.
+ You must inherit from
+ [`nuntius.models.AbstractSubscriber`](https://github.com/lafranceinsoumise/nuntius/blob/master/nuntius/models.py#L174)
+ and implement all the necessary methods. An easy way to do this is to use directly or to extend
+ [`BaseSubscriber`](https://github.com/lafranceinsoumise/nuntius/blob/master/nuntius/models.py#L204), but
+ you can implement the methods of `AbstractSubscriber` the way you want.
+
+ Here are the methods you must implement :
+
+ * `get_subscriber_status()`
+ must return one of `AbstractSubscriber.STATUS_CHOICES`. You can also simply
+ define a `subscriber_status` attribute.
+
+ * `get_subscriber_email()`
+ must return a unique email address for the subscriber. You can also simply
+ define an `email` attribute.
+
+ * `get_subscriber_data()`
+ must return the dictionnary of values which can be used as substitution in
+ the emails. Default is `{"email": self.get_subscriber_email()}`.
+
+ * `get_subscriber_push_devices()` (optional)
+ must return a list of `django-push-notifications.APNSDevice`
+ and `django-push-notifications.GCMDevice` model instances
+ (cf. [the `django-push-notifications` documentation](https://github.com/jazzband/django-push-notifications))
+
+
+
+4. Tell Nuntius how to find your subscriber model in `settings.py`
+ ````python
+ NUNTIUS_SUBSCRIBER_MODEL = 'myapp.MySubscriberModel'
+ ````
+
+5. Launch the nuntius worker in the background. In a production setting, this should be done through
+ a process monitor like upstart or systemd.
+ ```shell script
+ export DJANGO_SETTINGS_MODULE=myapp.settings
+ python ./manage.py nuntius_worker
+ ```
+
+6. Unless you are using a custom admin site, admin panels for Nuntius will be
+[autodiscovered](https://docs.djangoproject.com/en/2.0/ref/contrib/admin/#discovery-of-admin-files)
+and added to you admin site. If you use a custom admin site, you need to register
+Nuntius models with something like:
+
+ ```python
+ admin_site.register(nuntius.models.Campaign, nuntius.admin.CampaignAdmin)
+ admin_site.register(nuntius.models.CampaignSentEvent, nuntius.admin.CampaignSentEventAdmin)
+ ```
+
+## Other settings
+Use `NUNTIUS_DEFAULT_FROM_EMAIL`, `NUNTIUS_DEFAULT_FROM_NAME`, `NUNTIUS_DEFAULT_REPLY_TO_EMAIL`,
+`NUNTIUS_DEFAULT_REPLY_TO_NAME` to change default field values in the admin form.
+
+Use `NUNTIUS_ENABLED_CAMPAIGN_TYPES` to choose which types of campaign
+you want to enable by default (`email` *default*, `push` or `email,push`)
+
+In order to use push notifications, `NUNTIUS_PUSH_NOTIFICATION_SETTINGS` must be specified
+(cf. [the `django-push-notifications` documentation](https://github.com/jazzband/django-push-notifications#settings-list))
+```py
+NUNTIUS_PUSH_NOTIFICATIONS_SETTINGS = {
+ "FCM_API_KEY": "[your api key]",
+ "GCM_API_KEY": "[your api key]",
+ "APNS_CERTIFICATE": "/path/to/your/certificate.pem",
+ "APNS_TOPIC": "com.example.push_test",
+ # ...
+}
+```
+
+## Advanced usage
+
+### List segments
+
+If you want to have more control on your recipients, you can create a
+segment model.
+
+One example of segment is a simple model which holds a Many-to-Many relation
+to subscribers.
+
+Another example is a segment model which filters subscribers depending on
+the date of their last login :
+
+```python
+from django.db import models
+from django.db.models import fields
+from datetime import datetime
+
+from nuntius.models import BaseSegment
+
+
+class LastLoginDateSegment(BaseSegment, models.Model):
+ last_login_duration = fields.DurationField()
+
+ def get_display_name(self):
+ return f'Last login : {str(datetime.now() - self.last_login_duration)}'
+
+ def get_subscribers_queryset(self):
+ return MySubscriberClass.objects.filter(last_login__gt=datetime.now() - self.last_login_duration)
+
+ def get_subscribers_count(self):
+ return MySubscriberClass.objects.filter(last_login__gt=datetime.now() - self.last_login_duration, subscribed=True)
+
+```
+
+* `get_subscribers_queryset` is allowed to return subscribers regardless of their
+ `subscriber_status`, as `get_subscriber_status` will be called on each instance.
+* `get_subscribers_count` is only there for convenience in the admin panel, it does not
+ have to be accurate. If you want to have it accurate, you should however take
+ your subscribers status into account.
+
+Then, add your segment model to Nuntius settings :
+````python
+NUNTIUS_SEGMENT_MODEL = 'myapp.lastlogindatesegment'
+````
+
+### Custom template
+
+You can write your own Mosaico template to fit your needs. To make it available in the admin,
+list the public URL path of the template in `NUNTIUS_MOSAICO_TEMPLATES`. The template can be served
+by Django static files system, or any other way at your preference.
+
+```python
+NUNTIUS_MOSAICO_TEMPLATES = [
+ ("/static/mosaico_templates/versafix-2/template-versafix-2.html", "Custom template")
+]
+```
+
+### Sending parameters
+
+The worker will spawn several subprocesses to speed up the sending of campaigns. The number of
+processes that will send emails concurrently can be configured using the `NUNTIUS_MAX_CONCURRENT_SENDERS`
+setting.
+
+Most ESP enforce a maximum send rate. Nuntius won't sent messages faster than`NUNTIUS_MAX_SENDING_RATE`,
+in messages per second.
+
+When using SMTP, some ESP limit the number of emails that can be sent using a single connection.
+`NUNTIUS_MAX_MESSAGES_PER_CONNECTION` will force Nuntius to reset the connection after sending that
+many messages.
+
+The Nuntius worker checks every `NUNTIUS_POLLING_INTERVAL` seconds if any sending has been scheduled
+or canceled. The default value of 2 seconds should be find for most usages.
+
+To help you configure these parameters, you can send SIGUSR1 to the main worker process and it will
+print sending statistics on `stderr`. Pay special attention to the current sending rate and to the
+current bucket capacity: if your sending rate is lower than the maximum you configured, it most
+likely means the value you chose for `NUNTIUS_MAX_CONCURRENT_SENDERS` is not high enough given
+the latency you're getting with your ESP.
+
+### ESP and Webhooks
+
+Maintaining your own SMTP server to send your newsletter is probably
+a bad idea if you have more than a few subscribers. You can use
+[Anymail](https://github.com/anymail/django-anymail) along with Nuntius
+in order to use an email service provider. Anymail supports
+a lot of ESP, like Amazon SES, Mailgun, Mailjet, Postmark, SendGrid,
+SendinBlue, or SparkPost.
+
+Refer to the steps in [Anymail 1-2-3](https://anymail.readthedocs.io/en/stable/quickstart/)
+to install Anymail. If you want to configure Anymail just for Nuntius and keep
+the default email backend for other usage, you can use the setting `NUNTIUS_EMAIL_BACKEND`
+rather than the default `EMAIL_BACKEND`.
+
+In addition, configuring Nuntius with Anymail will allow you to use ESP tracking features
+and to track status of your email once it is sent.
+
+#### Webhooks
+
+Configuring webhhoks allows Nuntius to track email status and to
+give you statistics on campaign, as well as updating subscriber status
+when they bounce.
+
+1. Configure email tracking as described in
+[Anymail documentation](https://anymail.readthedocs.io/en/stable/installation/#configuring-tracking-and-inbound-webhooks).
+2. Implement the method `set_subscriber_status(self, email, status)` on your subscriber
+model manager.
+
+Nuntius will automatically listen to Anymail signals and call this method if needed.
+
+##### Handling of non-nuntius events (optional)
+
+If you send emails to your subscribers by other means than Nuntius (for example,
+transactional emails), you will receive webhooks events which are not related to
+a campaign you sent. By default, Nuntius will create a campaign result event recording
+the email and the event type, but it will not link it to a campaign nor to a subscriber
+model.
+
+If you want your events to always be linked to a subscriber model, you must implement
+a `get_subscriber(self, email_address)` method on your subscriber model manager.
+
+
+##### BaseSubscriberManager
+
+Nuntius is packaged with a BaseSubscriberManager, which implements both
+`set_subscriber_status` and `get_subscriber`, assuming you have an `email` field
+on your subscriber model. This is the default manager used by `BaseSubscriber`.
+
+
+#### Bounce handling
+
+Most ESP gives you a reputation based on your hard bounce rate.
+Mosaico handles bounces smartly to change your subscribers status
+when necessary.
+
+If Nuntius receive a bounce event on an email address which has no
+other sending event, `set_subscriber_status(email, status)` is called
+with `AbstractSubscriber.STATUS_BOUNCED`.
+
+If a successful sending event exists for this address,
+three parameters are taken into account :
+* if during the last `duration` days, there has been no more bounces than `limit`
+and at least one successful sending, no action is taken
+* if there has been at least one successful sending in the last
+`consecutive` events, no action is taken
+* otherwise, `set_subscriber_status(email, status)` is called
+with `AbstractSubscriber.STATUS_BOUNCED`
+
+
+You can change thoses default values :
+```python
+NUNTIUS_BOUNCE_PARAMS = {
+ "consecutive": 1,
+ "duration": 7,
+ "limit": 3
+}
+```
+
+**Example :**
+
+* You send 3 campaigns a week. After a few months, a subscriber
+has a full mailbox. On first and second bounced campaign, no action
+is taken because there is a successful sending in the last 7 days,
+and no more than 3 bounces. On the third campaign, if the user has empty
+their mailbox, everything is fine. Otherwise, the subscriber is marked
+as permanently bounced.
+* You send one campaign a day. A user has a buggy email server.
+This week, the user has already 3 bounces. When you receive the 4th
+bounce, if there has been a successful sending just before,
+everything is fine. Otherwise, the subscriber is marked
+as permanently bounced.
+
+## Tracking
+
+Opening and clicks are tracked by adding a white pixel and replacing links in emails, and by using a proxy URL on
+push notification clicks.
+
+Nuntius also adds [UTM parameters](https://en.wikipedia.org/wiki/UTM_parameters) to every URL with the following values:
+* `utm_source`: *"nuntius"*
+* `utm_medium`: *"email"*
+* `utm_campaign`: value configured by user at the campaign level
+* `utm_content`: *"link-{number}"* based on the link position in the email
+* `utm_term`: attribute `utm_term` of the segment object, or empty string if attribute does not exist
+
+In some situations, two details may be important for you:
+
+1. `utm_campaign`, `utm_content`, and `utm_term`, those are just defaults values, and can also be set directly on
+the link. `utm_source` and `utm_medium` will always be overwritten.
+2. `utm_content` and `utm_term` are set at sending time and cannot change afterwards. `utm_campaign` is
+set at click time, during the redirection from nuntius tracking URL to target URL, so if you change the value
+at the campaign level after sending, the value will change for all new clicks.
+
+## License
+
+Copyright is owned by Jill Royer and Arthur Cheysson.
+
+You can use Nuntius under GPLv3 terms.
+
+
+%package help
+Summary: Development documents and examples for nuntius
+Provides: python3-nuntius-doc
+%description help
+# Nuntius
+
+Nuntius is a newsletter / push notification campaign application for Django.
+
+Nuntius integrates with your Django project.
+It is very agnostic about your subscribers and subscriber lists models.
+
+It features [Mosaico](https://mosaico.io/), a drag-and-drop email
+editor, for sending beautiful emails to your subscribers and
+push notification support through Apple Push Notification service (APNs)
+and Google Cloud Messaging (GCM).
+
+## How it works
+
+Nuntius is agnostic about your subscribers model. You can use your current
+use model, as long as it implements a few required methods.
+
+To allow your end-users to choose recipients, it is your choice to implement
+one or more "segment" models. Segment models implement a required method
+`get_subscribers_queryset`.
+
+You can then create campaigns in the Django admin panel, and send them to
+existing segments.
+
+## Installation
+
+1. Add "push_notifications" and "nuntius" to your INSTALLED_APPS setting like this:
+ ````python
+ INSTALLED_APPS = [
+ 'django.contrib.admin',
+ 'django.contrib.auth',
+ 'django.contrib.contenttypes',
+ 'django.contrib.sessions',
+ 'django.contrib.messages',
+ 'django.contrib.staticfiles',
+ ...
+ 'push_notifications',
+ 'nuntius',
+ ]
+ ````
+2. Include Nuntius urlconf in your project `urls.py` like this:
+ ````python
+ path('nuntius/', include('nuntius.urls')),
+ ````
+3. Define your subscriber model so it works with Nuntius.
+ You must inherit from
+ [`nuntius.models.AbstractSubscriber`](https://github.com/lafranceinsoumise/nuntius/blob/master/nuntius/models.py#L174)
+ and implement all the necessary methods. An easy way to do this is to use directly or to extend
+ [`BaseSubscriber`](https://github.com/lafranceinsoumise/nuntius/blob/master/nuntius/models.py#L204), but
+ you can implement the methods of `AbstractSubscriber` the way you want.
+
+ Here are the methods you must implement :
+
+ * `get_subscriber_status()`
+ must return one of `AbstractSubscriber.STATUS_CHOICES`. You can also simply
+ define a `subscriber_status` attribute.
+
+ * `get_subscriber_email()`
+ must return a unique email address for the subscriber. You can also simply
+ define an `email` attribute.
+
+ * `get_subscriber_data()`
+ must return the dictionnary of values which can be used as substitution in
+ the emails. Default is `{"email": self.get_subscriber_email()}`.
+
+ * `get_subscriber_push_devices()` (optional)
+ must return a list of `django-push-notifications.APNSDevice`
+ and `django-push-notifications.GCMDevice` model instances
+ (cf. [the `django-push-notifications` documentation](https://github.com/jazzband/django-push-notifications))
+
+
+
+4. Tell Nuntius how to find your subscriber model in `settings.py`
+ ````python
+ NUNTIUS_SUBSCRIBER_MODEL = 'myapp.MySubscriberModel'
+ ````
+
+5. Launch the nuntius worker in the background. In a production setting, this should be done through
+ a process monitor like upstart or systemd.
+ ```shell script
+ export DJANGO_SETTINGS_MODULE=myapp.settings
+ python ./manage.py nuntius_worker
+ ```
+
+6. Unless you are using a custom admin site, admin panels for Nuntius will be
+[autodiscovered](https://docs.djangoproject.com/en/2.0/ref/contrib/admin/#discovery-of-admin-files)
+and added to you admin site. If you use a custom admin site, you need to register
+Nuntius models with something like:
+
+ ```python
+ admin_site.register(nuntius.models.Campaign, nuntius.admin.CampaignAdmin)
+ admin_site.register(nuntius.models.CampaignSentEvent, nuntius.admin.CampaignSentEventAdmin)
+ ```
+
+## Other settings
+Use `NUNTIUS_DEFAULT_FROM_EMAIL`, `NUNTIUS_DEFAULT_FROM_NAME`, `NUNTIUS_DEFAULT_REPLY_TO_EMAIL`,
+`NUNTIUS_DEFAULT_REPLY_TO_NAME` to change default field values in the admin form.
+
+Use `NUNTIUS_ENABLED_CAMPAIGN_TYPES` to choose which types of campaign
+you want to enable by default (`email` *default*, `push` or `email,push`)
+
+In order to use push notifications, `NUNTIUS_PUSH_NOTIFICATION_SETTINGS` must be specified
+(cf. [the `django-push-notifications` documentation](https://github.com/jazzband/django-push-notifications#settings-list))
+```py
+NUNTIUS_PUSH_NOTIFICATIONS_SETTINGS = {
+ "FCM_API_KEY": "[your api key]",
+ "GCM_API_KEY": "[your api key]",
+ "APNS_CERTIFICATE": "/path/to/your/certificate.pem",
+ "APNS_TOPIC": "com.example.push_test",
+ # ...
+}
+```
+
+## Advanced usage
+
+### List segments
+
+If you want to have more control on your recipients, you can create a
+segment model.
+
+One example of segment is a simple model which holds a Many-to-Many relation
+to subscribers.
+
+Another example is a segment model which filters subscribers depending on
+the date of their last login :
+
+```python
+from django.db import models
+from django.db.models import fields
+from datetime import datetime
+
+from nuntius.models import BaseSegment
+
+
+class LastLoginDateSegment(BaseSegment, models.Model):
+ last_login_duration = fields.DurationField()
+
+ def get_display_name(self):
+ return f'Last login : {str(datetime.now() - self.last_login_duration)}'
+
+ def get_subscribers_queryset(self):
+ return MySubscriberClass.objects.filter(last_login__gt=datetime.now() - self.last_login_duration)
+
+ def get_subscribers_count(self):
+ return MySubscriberClass.objects.filter(last_login__gt=datetime.now() - self.last_login_duration, subscribed=True)
+
+```
+
+* `get_subscribers_queryset` is allowed to return subscribers regardless of their
+ `subscriber_status`, as `get_subscriber_status` will be called on each instance.
+* `get_subscribers_count` is only there for convenience in the admin panel, it does not
+ have to be accurate. If you want to have it accurate, you should however take
+ your subscribers status into account.
+
+Then, add your segment model to Nuntius settings :
+````python
+NUNTIUS_SEGMENT_MODEL = 'myapp.lastlogindatesegment'
+````
+
+### Custom template
+
+You can write your own Mosaico template to fit your needs. To make it available in the admin,
+list the public URL path of the template in `NUNTIUS_MOSAICO_TEMPLATES`. The template can be served
+by Django static files system, or any other way at your preference.
+
+```python
+NUNTIUS_MOSAICO_TEMPLATES = [
+ ("/static/mosaico_templates/versafix-2/template-versafix-2.html", "Custom template")
+]
+```
+
+### Sending parameters
+
+The worker will spawn several subprocesses to speed up the sending of campaigns. The number of
+processes that will send emails concurrently can be configured using the `NUNTIUS_MAX_CONCURRENT_SENDERS`
+setting.
+
+Most ESP enforce a maximum send rate. Nuntius won't sent messages faster than`NUNTIUS_MAX_SENDING_RATE`,
+in messages per second.
+
+When using SMTP, some ESP limit the number of emails that can be sent using a single connection.
+`NUNTIUS_MAX_MESSAGES_PER_CONNECTION` will force Nuntius to reset the connection after sending that
+many messages.
+
+The Nuntius worker checks every `NUNTIUS_POLLING_INTERVAL` seconds if any sending has been scheduled
+or canceled. The default value of 2 seconds should be find for most usages.
+
+To help you configure these parameters, you can send SIGUSR1 to the main worker process and it will
+print sending statistics on `stderr`. Pay special attention to the current sending rate and to the
+current bucket capacity: if your sending rate is lower than the maximum you configured, it most
+likely means the value you chose for `NUNTIUS_MAX_CONCURRENT_SENDERS` is not high enough given
+the latency you're getting with your ESP.
+
+### ESP and Webhooks
+
+Maintaining your own SMTP server to send your newsletter is probably
+a bad idea if you have more than a few subscribers. You can use
+[Anymail](https://github.com/anymail/django-anymail) along with Nuntius
+in order to use an email service provider. Anymail supports
+a lot of ESP, like Amazon SES, Mailgun, Mailjet, Postmark, SendGrid,
+SendinBlue, or SparkPost.
+
+Refer to the steps in [Anymail 1-2-3](https://anymail.readthedocs.io/en/stable/quickstart/)
+to install Anymail. If you want to configure Anymail just for Nuntius and keep
+the default email backend for other usage, you can use the setting `NUNTIUS_EMAIL_BACKEND`
+rather than the default `EMAIL_BACKEND`.
+
+In addition, configuring Nuntius with Anymail will allow you to use ESP tracking features
+and to track status of your email once it is sent.
+
+#### Webhooks
+
+Configuring webhhoks allows Nuntius to track email status and to
+give you statistics on campaign, as well as updating subscriber status
+when they bounce.
+
+1. Configure email tracking as described in
+[Anymail documentation](https://anymail.readthedocs.io/en/stable/installation/#configuring-tracking-and-inbound-webhooks).
+2. Implement the method `set_subscriber_status(self, email, status)` on your subscriber
+model manager.
+
+Nuntius will automatically listen to Anymail signals and call this method if needed.
+
+##### Handling of non-nuntius events (optional)
+
+If you send emails to your subscribers by other means than Nuntius (for example,
+transactional emails), you will receive webhooks events which are not related to
+a campaign you sent. By default, Nuntius will create a campaign result event recording
+the email and the event type, but it will not link it to a campaign nor to a subscriber
+model.
+
+If you want your events to always be linked to a subscriber model, you must implement
+a `get_subscriber(self, email_address)` method on your subscriber model manager.
+
+
+##### BaseSubscriberManager
+
+Nuntius is packaged with a BaseSubscriberManager, which implements both
+`set_subscriber_status` and `get_subscriber`, assuming you have an `email` field
+on your subscriber model. This is the default manager used by `BaseSubscriber`.
+
+
+#### Bounce handling
+
+Most ESP gives you a reputation based on your hard bounce rate.
+Mosaico handles bounces smartly to change your subscribers status
+when necessary.
+
+If Nuntius receive a bounce event on an email address which has no
+other sending event, `set_subscriber_status(email, status)` is called
+with `AbstractSubscriber.STATUS_BOUNCED`.
+
+If a successful sending event exists for this address,
+three parameters are taken into account :
+* if during the last `duration` days, there has been no more bounces than `limit`
+and at least one successful sending, no action is taken
+* if there has been at least one successful sending in the last
+`consecutive` events, no action is taken
+* otherwise, `set_subscriber_status(email, status)` is called
+with `AbstractSubscriber.STATUS_BOUNCED`
+
+
+You can change thoses default values :
+```python
+NUNTIUS_BOUNCE_PARAMS = {
+ "consecutive": 1,
+ "duration": 7,
+ "limit": 3
+}
+```
+
+**Example :**
+
+* You send 3 campaigns a week. After a few months, a subscriber
+has a full mailbox. On first and second bounced campaign, no action
+is taken because there is a successful sending in the last 7 days,
+and no more than 3 bounces. On the third campaign, if the user has empty
+their mailbox, everything is fine. Otherwise, the subscriber is marked
+as permanently bounced.
+* You send one campaign a day. A user has a buggy email server.
+This week, the user has already 3 bounces. When you receive the 4th
+bounce, if there has been a successful sending just before,
+everything is fine. Otherwise, the subscriber is marked
+as permanently bounced.
+
+## Tracking
+
+Opening and clicks are tracked by adding a white pixel and replacing links in emails, and by using a proxy URL on
+push notification clicks.
+
+Nuntius also adds [UTM parameters](https://en.wikipedia.org/wiki/UTM_parameters) to every URL with the following values:
+* `utm_source`: *"nuntius"*
+* `utm_medium`: *"email"*
+* `utm_campaign`: value configured by user at the campaign level
+* `utm_content`: *"link-{number}"* based on the link position in the email
+* `utm_term`: attribute `utm_term` of the segment object, or empty string if attribute does not exist
+
+In some situations, two details may be important for you:
+
+1. `utm_campaign`, `utm_content`, and `utm_term`, those are just defaults values, and can also be set directly on
+the link. `utm_source` and `utm_medium` will always be overwritten.
+2. `utm_content` and `utm_term` are set at sending time and cannot change afterwards. `utm_campaign` is
+set at click time, during the redirection from nuntius tracking URL to target URL, so if you change the value
+at the campaign level after sending, the value will change for all new clicks.
+
+## License
+
+Copyright is owned by Jill Royer and Arthur Cheysson.
+
+You can use Nuntius under GPLv3 terms.
+
+
+%prep
+%autosetup -n nuntius-2.3.2
+
+%build
+%py3_build
+
+%install
+%py3_install
+install -d -m755 %{buildroot}/%{_pkgdocdir}
+if [ -d doc ]; then cp -arf doc %{buildroot}/%{_pkgdocdir}; fi
+if [ -d docs ]; then cp -arf docs %{buildroot}/%{_pkgdocdir}; fi
+if [ -d example ]; then cp -arf example %{buildroot}/%{_pkgdocdir}; fi
+if [ -d examples ]; then cp -arf examples %{buildroot}/%{_pkgdocdir}; fi
+pushd %{buildroot}
+if [ -d usr/lib ]; then
+ find usr/lib -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/lib64 ]; then
+ find usr/lib64 -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/bin ]; then
+ find usr/bin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+if [ -d usr/sbin ]; then
+ find usr/sbin -type f -printf "/%h/%f\n" >> filelist.lst
+fi
+touch doclist.lst
+if [ -d usr/share/man ]; then
+ find usr/share/man -type f -printf "/%h/%f.gz\n" >> doclist.lst
+fi
+popd
+mv %{buildroot}/filelist.lst .
+mv %{buildroot}/doclist.lst .
+
+%files -n python3-nuntius -f filelist.lst
+%dir %{python3_sitelib}/*
+
+%files help -f doclist.lst
+%{_docdir}/*
+
+%changelog
+* Thu May 18 2023 Python_Bot <Python_Bot@openeuler.org> - 2.3.2-1
+- Package Spec generated