subman


Namesubman JSON
Version 0.1.1 PyPI version JSON
download
home_pagehttps://github.com/cde-ev/subman
SummaryPowerful Python package to manage subscriptions.
upload_time2023-11-22 00:52:21
maintainerCdE-Datenbank development team
docs_urlNone
authorLars Esser, Maarten Grothus, Tobias Udtke
requires_python>=3.8
license
keywords subscription mailinglist opt-out
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            Subman
======

Subman uses a fairly complex state schema to manage subscription states
internally. Its behavior can be configured using the ``SubscriptionManager``,
which is also the main interface of the library.

.. figure:: SubscriptionStates.png
    :width: 70 %
    :alt: Subscription state schema
    :align: center
    :figclass: align-center

    This graphic was created using `Draw.io <https://draw.io>`_.
    To edit it, upload the SubscriptionState.png file there.

Subman uses a total of seven distinct states, which allow a consistent and
useful subscription management, even if the condition for list membership change.
Of these, four states are so-called core states, without which the software can not
function properly, while the other states are optional.

Every transition between these states is modeled by a corresponding ``SubscriptionAction``,
which are shown as arrows in the graph. While most subscription actions act on multiple
states, there is always a unique target state associated with each action.

Subman includes a distinction between action which require additional privileges
(possibly depending on the list in question). These privileged users are referred to as
"moderators". Actions restricted to moderators are referred to as "managing actions".

In addition to the manual actions which can be performed, it is required to
regularly perform cleanup actions to react to changes in implicators.
This actually does not make use of the ``SubscriptionAction`` enum, but makes use of
its own internal state transitioning logic given in
``SubscriptionManager._apply_cleanup()``.

In subman, we differentiate between subscribing (shown in green in the graph)
and non-subscribing states (shown in red), where users
listed in subscribing states are considered to be subscribed in the usual sense.
For subscribers, there is no visible distinction between the different
subscribing states intended.

List of states
--------------
Subscribing states are:

Explicitly Subscribed (Core)
    Users, which have been actively subscribed to a list, either by
    themselves or by a moderator, are saved as explicitly subscribed.
    If these users have no more means to access a list, for example because they
    lost club membership, or because they no longer attend an event, they are removed
    from the list.
    Lists without special membership implicators only have explicit subscribers.

Subscription Override (Optional)
    Subscription Overrides are a special kind of explicit subscriptions, which are
    kept even if the user should not be able to access a list. However,
    if a list allows unsubscribing in general, they do not prevent a user from
    unsubscribing themselves.
    The list of Subscription Overrides should be accessible for moderators.

Implicitly Subscribed (Core)
    Users, which are subscribed to a list, because they meet some condition,
    are listed as implicit subscribers. Typical examples are lists having all
    members or all attendees of an event or assembly as implicit subscribers. If users
    lose the automatic implicator that subscribes them to the list, they are
    removed even if they would still be able to access it.

    It is optional to store implicit subscribers explicitly. Otherwise, they have to
    be calculated at runtime.

Non-subscribing states are:

Implicitly Unsubscribed (Core)
    This is the standard state for users having no relationship to a list
    whatsoever, because they never were listed on it or lost access to it.

    It is optional to store this state explicitly.

.. _Explicitly_Unsubscribed:

Explicitly Unsubscribed (Core)
    Users, who have stated to not want to receive information from a
    specific list anymore. This decision is permanent, until manually
    reverted by them or a moderator. Even if they lose access to a list, this
    information is kept. Thus, if they regain access later on, these users
    will not be receiving information from it.
    However, if they are explicitly subscribed again, they do not receive
    special treatment.

    Due to this fact, users tend to get "stuck" in this case, since it is not
    cleaned up automatically. For example, every user who has been manually
    removed from a list by a moderator, will stay here forever without
    further intervention. While the state transitions are designed with this
    in mind, making no difference between manual actions on explicitly and
    implicitly unsubscribed users, it is still possible for moderators to
    cleanup explicit unsubscriptions to implicit subscriptions.

    To not obstruct the design of the state schema, this should only be used
    to cleanup test cases or to prepare for the use of tools which might be
    obstructed by explicit unsubscriptions.

Unsubscription Override (Optional)
    Unsubscription Overrides are a special kind of explicit unsubscriptions, which
    can not be removed by the affected user. Except for mandatory lists, they
    can be used to block a specific user from any kind of subscription or
    subscription request.
    The list of Unsubscription Overrides should be accessible for moderators.

Request Pending (Optional)
    This is a special case only existing for mailinglists with moderated opt-in
    subscription policy for a group of users.
    Users with pending subscription requests are displayed on a
    specific list to moderators, so they can decide if they want to approve or
    deny their request. It is also possible to block further requests by this
    user.

When changing the ``SubscriptionPolicy`` associated to a certain list, subman
can handle updating its subscribers automatically. However, if the list is set
to ``allow_unsub = False``, all users with explicit unsubscriptions,
including Unsubscription Overrides, need to be cleaned up during the transition.
If subman detects this has not been done, it will raise an error.

Usage example
-------------
For a comprehensive example of the use of subman, we recommend taking a look at
the ml realm of the `CdEDBv2 <https://github.com/cde-ev/cdedb2>`_.
There, subman is used to support complex mailinglist management by subscribers
and moderators.
The subscription state data is saved into a SQL database, except for
``SubscriptionState.none``, and includes a logging of each ``SubscriptionAction``.

.. |subman_example.py| image:: subman_example.py

However, a minimal example class can be realized as shown in |subman_example.py|.
This is basically a really streamlined version of the
`CdEDBv2 <https://github.com/cde-ev/cdedb2>`_ MlBackend.

Internationalization
--------------------
Like the `CdEDBv2 <https://github.com/cde-ev/cdedb2>`_, subman is internationalized
using GNU gettext. By adding translations for the respective strings, users of the
library can customize error messages to their heart's content.

            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/cde-ev/subman",
    "name": "subman",
    "maintainer": "CdE-Datenbank development team",
    "docs_url": null,
    "requires_python": ">=3.8",
    "maintainer_email": "cdedb@lists.cde-ev.de",
    "keywords": "subscription,mailinglist,opt-out",
    "author": "Lars Esser, Maarten Grothus, Tobias Udtke",
    "author_email": "",
    "download_url": "https://files.pythonhosted.org/packages/41/e9/6cfe001400ce50e2c87e3650db5be352aa98732db21616a0ceffb4d2e811/subman-0.1.1.tar.gz",
    "platform": null,
    "description": "Subman\n======\n\nSubman uses a fairly complex state schema to manage subscription states\ninternally. Its behavior can be configured using the ``SubscriptionManager``,\nwhich is also the main interface of the library.\n\n.. figure:: SubscriptionStates.png\n    :width: 70 %\n    :alt: Subscription state schema\n    :align: center\n    :figclass: align-center\n\n    This graphic was created using `Draw.io <https://draw.io>`_.\n    To edit it, upload the SubscriptionState.png file there.\n\nSubman uses a total of seven distinct states, which allow a consistent and\nuseful subscription management, even if the condition for list membership change.\nOf these, four states are so-called core states, without which the software can not\nfunction properly, while the other states are optional.\n\nEvery transition between these states is modeled by a corresponding ``SubscriptionAction``,\nwhich are shown as arrows in the graph. While most subscription actions act on multiple\nstates, there is always a unique target state associated with each action.\n\nSubman includes a distinction between action which require additional privileges\n(possibly depending on the list in question). These privileged users are referred to as\n\"moderators\". Actions restricted to moderators are referred to as \"managing actions\".\n\nIn addition to the manual actions which can be performed, it is required to\nregularly perform cleanup actions to react to changes in implicators.\nThis actually does not make use of the ``SubscriptionAction`` enum, but makes use of\nits own internal state transitioning logic given in\n``SubscriptionManager._apply_cleanup()``.\n\nIn subman, we differentiate between subscribing (shown in green in the graph)\nand non-subscribing states (shown in red), where users\nlisted in subscribing states are considered to be subscribed in the usual sense.\nFor subscribers, there is no visible distinction between the different\nsubscribing states intended.\n\nList of states\n--------------\nSubscribing states are:\n\nExplicitly Subscribed (Core)\n    Users, which have been actively subscribed to a list, either by\n    themselves or by a moderator, are saved as explicitly subscribed.\n    If these users have no more means to access a list, for example because they\n    lost club membership, or because they no longer attend an event, they are removed\n    from the list.\n    Lists without special membership implicators only have explicit subscribers.\n\nSubscription Override (Optional)\n    Subscription Overrides are a special kind of explicit subscriptions, which are\n    kept even if the user should not be able to access a list. However,\n    if a list allows unsubscribing in general, they do not prevent a user from\n    unsubscribing themselves.\n    The list of Subscription Overrides should be accessible for moderators.\n\nImplicitly Subscribed (Core)\n    Users, which are subscribed to a list, because they meet some condition,\n    are listed as implicit subscribers. Typical examples are lists having all\n    members or all attendees of an event or assembly as implicit subscribers. If users\n    lose the automatic implicator that subscribes them to the list, they are\n    removed even if they would still be able to access it.\n\n    It is optional to store implicit subscribers explicitly. Otherwise, they have to\n    be calculated at runtime.\n\nNon-subscribing states are:\n\nImplicitly Unsubscribed (Core)\n    This is the standard state for users having no relationship to a list\n    whatsoever, because they never were listed on it or lost access to it.\n\n    It is optional to store this state explicitly.\n\n.. _Explicitly_Unsubscribed:\n\nExplicitly Unsubscribed (Core)\n    Users, who have stated to not want to receive information from a\n    specific list anymore. This decision is permanent, until manually\n    reverted by them or a moderator. Even if they lose access to a list, this\n    information is kept. Thus, if they regain access later on, these users\n    will not be receiving information from it.\n    However, if they are explicitly subscribed again, they do not receive\n    special treatment.\n\n    Due to this fact, users tend to get \"stuck\" in this case, since it is not\n    cleaned up automatically. For example, every user who has been manually\n    removed from a list by a moderator, will stay here forever without\n    further intervention. While the state transitions are designed with this\n    in mind, making no difference between manual actions on explicitly and\n    implicitly unsubscribed users, it is still possible for moderators to\n    cleanup explicit unsubscriptions to implicit subscriptions.\n\n    To not obstruct the design of the state schema, this should only be used\n    to cleanup test cases or to prepare for the use of tools which might be\n    obstructed by explicit unsubscriptions.\n\nUnsubscription Override (Optional)\n    Unsubscription Overrides are a special kind of explicit unsubscriptions, which\n    can not be removed by the affected user. Except for mandatory lists, they\n    can be used to block a specific user from any kind of subscription or\n    subscription request.\n    The list of Unsubscription Overrides should be accessible for moderators.\n\nRequest Pending (Optional)\n    This is a special case only existing for mailinglists with moderated opt-in\n    subscription policy for a group of users.\n    Users with pending subscription requests are displayed on a\n    specific list to moderators, so they can decide if they want to approve or\n    deny their request. It is also possible to block further requests by this\n    user.\n\nWhen changing the ``SubscriptionPolicy`` associated to a certain list, subman\ncan handle updating its subscribers automatically. However, if the list is set\nto ``allow_unsub = False``, all users with explicit unsubscriptions,\nincluding Unsubscription Overrides, need to be cleaned up during the transition.\nIf subman detects this has not been done, it will raise an error.\n\nUsage example\n-------------\nFor a comprehensive example of the use of subman, we recommend taking a look at\nthe ml realm of the `CdEDBv2 <https://github.com/cde-ev/cdedb2>`_.\nThere, subman is used to support complex mailinglist management by subscribers\nand moderators.\nThe subscription state data is saved into a SQL database, except for\n``SubscriptionState.none``, and includes a logging of each ``SubscriptionAction``.\n\n.. |subman_example.py| image:: subman_example.py\n\nHowever, a minimal example class can be realized as shown in |subman_example.py|.\nThis is basically a really streamlined version of the\n`CdEDBv2 <https://github.com/cde-ev/cdedb2>`_ MlBackend.\n\nInternationalization\n--------------------\nLike the `CdEDBv2 <https://github.com/cde-ev/cdedb2>`_, subman is internationalized\nusing GNU gettext. By adding translations for the respective strings, users of the\nlibrary can customize error messages to their heart's content.\n",
    "bugtrack_url": null,
    "license": "",
    "summary": "Powerful Python package to manage subscriptions.",
    "version": "0.1.1",
    "project_urls": {
        "Bug Tracker": "https://github.com/cde-ev/subman/issues",
        "Homepage": "https://github.com/cde-ev/subman"
    },
    "split_keywords": [
        "subscription",
        "mailinglist",
        "opt-out"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "16750368ebae479f3529c012eb8edf238ed8e78dfff51d08669e92e5f29b5eea",
                "md5": "e899aa2acafceba78b24d33575f2ccad",
                "sha256": "0e83016a97120e718b573c33f816144671f7f2d2128292726ad96b3e7b7321e2"
            },
            "downloads": -1,
            "filename": "subman-0.1.1-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "e899aa2acafceba78b24d33575f2ccad",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.8",
            "size": 23717,
            "upload_time": "2023-11-22T00:52:20",
            "upload_time_iso_8601": "2023-11-22T00:52:20.203859Z",
            "url": "https://files.pythonhosted.org/packages/16/75/0368ebae479f3529c012eb8edf238ed8e78dfff51d08669e92e5f29b5eea/subman-0.1.1-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "41e96cfe001400ce50e2c87e3650db5be352aa98732db21616a0ceffb4d2e811",
                "md5": "dafdb8b3145dc3ade994ea526bc78419",
                "sha256": "f481793f5567d5b58092b13e9eb00d75e6abf7eb6ec3588d7d239e1f88f34449"
            },
            "downloads": -1,
            "filename": "subman-0.1.1.tar.gz",
            "has_sig": false,
            "md5_digest": "dafdb8b3145dc3ade994ea526bc78419",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.8",
            "size": 25741,
            "upload_time": "2023-11-22T00:52:21",
            "upload_time_iso_8601": "2023-11-22T00:52:21.380651Z",
            "url": "https://files.pythonhosted.org/packages/41/e9/6cfe001400ce50e2c87e3650db5be352aa98732db21616a0ceffb4d2e811/subman-0.1.1.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2023-11-22 00:52:21",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "cde-ev",
    "github_project": "subman",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "subman"
}
        
Elapsed time: 0.25444s