"Fossies" - the Fresh Open Source Software Archive

Member "mailman-3.3.7/src/mailman/rest/docs/addresses.rst" (10 Nov 2022, 20842 Bytes) of package /linux/misc/mailman-3.3.7.tar.bz2:


As a special service "Fossies" has tried to format the requested source page into HTML format (assuming markdown format). Alternatively you can here view or download the uninterpreted source code file. A member file download can also be achieved by clicking within a package contents listing on the according byte size field. See also the last Fossies "Diffs" side-by-side code changes report for "addresses.rst": 3.3.5_vs_3.3.6.

Addresses

The REST API can be used to manage addresses.

There are no addresses yet.

>>> from mailman.testing.documentation import dump_json >>> dump_json('http://localhost:9001/3.0/addresses') http_etag: "..." start: 0 total_size: 0

When an address is created via the internal API, it is available in the REST API. :

>>> from zope.component import getUtility
>>> from mailman.interfaces.usermanager import IUserManager
>>> user_manager = getUtility(IUserManager)
>>> anne = user_manager.create_address('anne@example.com')
>>> from mailman.config import config
>>> transaction = config.db    
>>> transaction.commit()

>>> dump_json('http://localhost:9001/3.0/addresses')
entry 0:
    email: anne@example.com
    http_etag: "..."
    original_email: anne@example.com
    registered_on: 2005-08-01T07:49:23
    self_link: http://localhost:9001/3.0/addresses/anne@example.com
http_etag: "..."
start: 0
total_size: 1

Anne's address can also be accessed directly.

>>> dump_json('http://localhost:9001/3.0/addresses/anne@example.com') email: anne@example.com http_etag: "..." original_email: anne@example.com registered_on: 2005-08-01T07:49:23 self_link: http://localhost:9001/3.0/addresses/anne@example.com

Bart registers with a mixed-case address. The canonical URL always includes the lower-case version.

>>> bart = user_manager.create_address('Bart.Person@example.com') >>> transaction.commit() >>> dump_json( ... 'http://localhost:9001/3.0/addresses/bart.person@example.com') email: bart.person@example.com http_etag: "..." original_email: Bart.Person@example.com registered_on: 2005-08-01T07:49:23 self_link: http://localhost:9001/3.0/addresses/bart.person@example.com

But his address record can be accessed with the case-preserved version too.

>>> dump_json( ... 'http://localhost:9001/3.0/addresses/Bart.Person@example.com') email: bart.person@example.com http_etag: "..." original_email: Bart.Person@example.com registered_on: 2005-08-01T07:49:23 self_link: http://localhost:9001/3.0/addresses/bart.person@example.com

When an address has a real name associated with it, this is also available in the REST API.

>>> cris = user_manager.create_address('cris@example.com', 'Cris Person') >>> transaction.commit() >>> dump_json('http://localhost:9001/3.0/addresses/cris@example.com') display_name: Cris Person email: cris@example.com http_etag: "..." original_email: cris@example.com registered_on: 2005-08-01T07:49:23 self_link: http://localhost:9001/3.0/addresses/cris@example.com

Verifying

When the address gets verified, this attribute is available in the REST representation.

>>> from mailman.utilities.datetime import now >>> anne.verified_on = now() >>> transaction.commit() >>> dump_json('http://localhost:9001/3.0/addresses/anne@example.com') email: anne@example.com http_etag: "..." original_email: anne@example.com registered_on: 2005-08-01T07:49:23 self_link: http://localhost:9001/3.0/addresses/anne@example.com verified_on: 2005-08-01T07:49:23

Addresses can also be verified through the REST API, by POSTing to the 'verify' sub-resource. The POST data is ignored.

>>> dump_json('http://localhost:9001/3.0/addresses/' ... 'cris@example.com/verify', {}) date: ... server: ... status: 204

Now Cris's address is verified.

>>> dump_json('http://localhost:9001/3.0/addresses/cris@example.com') display_name: Cris Person email: cris@example.com http_etag: "..." original_email: cris@example.com registered_on: 2005-08-01T07:49:23 self_link: http://localhost:9001/3.0/addresses/cris@example.com verified_on: 2005-08-01T07:49:23

If you should ever need to 'unverify' an address, POST to the 'unverify' sub-resource. Again, the POST data is ignored.

>>> dump_json('http://localhost:9001/3.0/addresses/' ... 'cris@example.com/unverify', {}) date: ... server: ... status: 204

Now Cris's address is unverified.

>>> dump_json('http://localhost:9001/3.0/addresses/cris@example.com') display_name: Cris Person email: cris@example.com http_etag: "..." original_email: cris@example.com registered_on: 2005-08-01T07:49:23 self_link: http://localhost:9001/3.0/addresses/cris@example.com

Updating

Each address has a display_name associated with it. This name can be updated by PATCH'ing the address resource:

>>> dump_json('http://localhost:9001/3.0/addresses/cris@example.com',
...           method='PATCH', data={'display_name': 'Cris P. Person'})
date: ...
server: ...
status: 204

This should update the display_name associated:

>>> dump_json('http://localhost:9001/3.0/addresses/cris@example.com')
display_name: Cris P. Person
email: cris@example.com
http_etag: "..."
original_email: cris@example.com
registered_on: 2005-08-01T07:49:23
self_link: http://localhost:9001/3.0/addresses/cris@example.com

The user

To link an address to a user, a POST request can be sent to the /user sub-resource of the address. If the user does not exist, it will be created.

>>> dump_json('http://localhost:9001/3.0/addresses/cris@example.com/user', ... {'display_name': 'Cris X. Person'}) content-length: 0 content-type: application/json date: ... location: http://localhost:9001/3.0/users/1 server: ... status: 201

The user is now created and the address is linked to it:

>>> cris.user <User "Cris X. Person" (1) at 0x...> >>> cris_user = user_manager.get_user('cris@example.com') >>> cris_user <User "Cris X. Person" (1) at 0x...> >>> cris.user == cris_user True >>> [a.email for a in cris_user.addresses] ['cris@example.com']

A link to the user resource is now available as a sub-resource.

>>> dump_json('http://localhost:9001/3.0/addresses/cris@example.com') display_name: Cris P. Person email: cris@example.com http_etag: "..." original_email: cris@example.com registered_on: 2005-08-01T07:49:23 self_link: http://localhost:9001/3.0/addresses/cris@example.com user: http://localhost:9001/3.0/users/1

To prevent automatic user creation from taking place, add the auto_create parameter to the POST request and set it to False.

>>> dump_json('http://localhost:9001/3.0/addresses/anne@example.com/user', ... {'display_name': 'Anne User', 'auto_create': False}) Traceback (most recent call last): ... urllib.error.HTTPError: HTTP Error 403: ...

A request to the /user sub-resource will return the linked user's representation:

>>> dump_json('http://localhost:9001/3.0/addresses/cris@example.com/user') created_on: 2005-08-01T07:49:23 display_name: Cris X. Person http_etag: "..." is_server_owner: False password: ... self_link: http://localhost:9001/3.0/users/1 user_id: 1

The address and the user can be unlinked by sending a DELETE request on the /user resource. The user itself is not deleted, only the link.

>>> dump_json('http://localhost:9001/3.0/addresses/cris@example.com/user', ... method='DELETE') date: ... server: ... status: 204 >>> transaction.abort() >>> cris.user == None True >>> from uuid import UUID >>> user_manager.get_user_by_id(UUID(int=1)) <User "Cris X. Person" (1) at 0x...> >>> dump_json('http://localhost:9001/3.0/addresses/cris@example.com/user') Traceback (most recent call last): ... urllib.error.HTTPError: HTTP Error 404: ...

You can link an existing user to an address by passing the user's ID in the POST request. :

>>> dump_json('http://localhost:9001/3.0/addresses/cris@example.com/user',
...           {'user_id': 1})
content-length: 0
content-type: application/json
date: ...
server: ...
status: 200

>>> dump_json('http://localhost:9001/3.0/addresses/cris@example.com/user')
created_on: ...
display_name: Cris X. Person
http_etag: ...
password: ...
self_link: http://localhost:9001/3.0/users/1
user_id: 1

To link an address to a different user, you can either send a DELETE request followed by a POST request, or you can send a PUT request. :

>>> dump_json('http://localhost:9001/3.0/addresses/cris@example.com/user',
...           {'display_name': 'Cris Q Person'}, method="PUT")
content-length: 0
content-type: application/json
date: ...
location: http://localhost:9001/3.0/users/2
server: ...
status: 201

>>> dump_json('http://localhost:9001/3.0/addresses/cris@example.com/user')
created_on: ...
display_name: Cris Q Person
http_etag: ...
password: ...
self_link: http://localhost:9001/3.0/users/2
user_id: 2

User addresses

Users control addresses. The canonical URLs for these user-controlled addresses live in the /addresses namespace. :

>>> dave = user_manager.create_user('dave@example.com', 'Dave Person')
>>> transaction.commit()
>>> dump_json('http://localhost:9001/3.0/users/dave@example.com/addresses')
entry 0:
    display_name: Dave Person
    email: dave@example.com
    http_etag: "..."
    original_email: dave@example.com
    registered_on: 2005-08-01T07:49:23
    self_link: http://localhost:9001/3.0/addresses/dave@example.com
    user: http://localhost:9001/3.0/users/3
http_etag: "..."
start: 0
total_size: 1

>>> dump_json('http://localhost:9001/3.0/addresses/dave@example.com')
display_name: Dave Person
email: dave@example.com
http_etag: "..."
original_email: dave@example.com
registered_on: 2005-08-01T07:49:23
self_link: http://localhost:9001/3.0/addresses/dave@example.com
user: http://localhost:9001/3.0/users/3

A user can be associated with multiple email addresses. You can add new addresses to an existing user.

>>> dump_json( ... 'http://localhost:9001/3.0/users/dave@example.com/addresses', { ... 'email': 'dave.person@example.org' ... }) content-length: 0 content-type: application/json date: ... location: http://localhost:9001/3.0/addresses/dave.person@example.org server: ... status: 201

When you add the new address, you can give it an optional display name.

>>> dump_json( ... 'http://localhost:9001/3.0/users/dave@example.com/addresses', { ... 'email': 'dp@example.org', ... 'display_name': 'Davie P', ... }) content-length: 0 content-type: application/json date: ... location: http://localhost:9001/3.0/addresses/dp@example.org server: ... status: 201

The user controls these new addresses.

>>> dump_json('http://localhost:9001/3.0/users/dave@example.com/addresses') entry 0: email: dave.person@example.org http_etag: "..." original_email: dave.person@example.org registered_on: 2005-08-01T07:49:23 self_link: http://localhost:9001/3.0/addresses/dave.person@example.org user: http://localhost:9001/3.0/users/3 entry 1: display_name: Dave Person email: dave@example.com http_etag: "..." original_email: dave@example.com registered_on: 2005-08-01T07:49:23 self_link: http://localhost:9001/3.0/addresses/dave@example.com user: http://localhost:9001/3.0/users/3 entry 2: display_name: Davie P email: dp@example.org http_etag: "..." original_email: dp@example.org registered_on: 2005-08-01T07:49:23 self_link: http://localhost:9001/3.0/addresses/dp@example.org user: http://localhost:9001/3.0/users/3 http_etag: "..." start: 0 total_size: 3

Preferred address

Each user can have a preferred address. Initially, every user's preferred address is unset. :

>>> ram = user_manager.create_user('ram@example.com', 'Ram Person')
>>> transaction.commit()
>>> dump_json(
...    'http://localhost:9001/3.1/users/ram@example.com/addresses')
entry 0:
    display_name: Ram Person
    email: ram@example.com
    http_etag: "..."
    original_email: ram@example.com
    registered_on: 2005-08-01T07:49:23
    self_link: http://localhost:9001/3.1/addresses/ram@example.com
    user: http://localhost:9001/3.1/users/00000000000000000000000000000004
http_etag: "..."
start: 0
total_size: 1
>>> import pdb
>>> dump_json('http://localhost:9001/3.1/users/ram@example.com/preferred_address')
Traceback (most recent call last):
...
urllib.error.HTTPError: HTTP Error 404: ...

Setting Ram's preferred addresses requires that it first be verified: :

>>> dump_json('http://localhost:9001/3.1/users/ram@example.com/preferred_address',
...     {'email': 'ram@example.com'})
Traceback (most recent call last):
...
urllib.error.HTTPError: HTTP Error 400: Ram Person <ram@example.com> must be verified before setting as primary

Verify Ram's address first: :

>>> addr = ram.addresses[0]
>>> addr.verified_on = now()
>>> transaction.commit()

Now, Ram can set his preferred address: :

>>> dump_json('http://localhost:9001/3.1/users/ram@example.com/preferred_address',
...     {'email': 'ram@example.com'})
content-length: 0
content-type: application/json
date: ...
location: http://localhost:9001/3.1/addresses/ram@example.com
server: ...
status: 201
>>> dump_json('http://localhost:9001/3.1/users/ram@example.com/preferred_address')
display_name: Ram Person
email: ram@example.com
http_etag: "..."
original_email: ram@example.com
registered_on: 2005-08-01T07:49:23
self_link: http://localhost:9001/3.1/addresses/ram@example.com
user: http://localhost:9001/3.1/users/00000000000000000000000000000004
verified_on: 2005-08-01T07:49:23

To unset Ram's preferred address, call a DELETE on preferred address resource: :

>>> dump_json('http://localhost:9001/3.1/users/ram@example.com/preferred_address',
...     method='DELETE')
date: ...
server: ...
status: 204

Memberships

Addresses can be subscribed to mailing lists. When they are, all the membership records for that address are easily accessible via the REST API.

Elle registers several email addresses.

>>> elle = user_manager.create_user('elle@example.com', 'Elle Person') >>> subscriber = list(elle.addresses)[0] >>> elle.register('eperson@example.com') <Address: eperson@example.com [not verified] at ...> >>> elle.register('elle.person@example.com') <Address: elle.person@example.com [not verified] at ...>

Elle subscribes to two mailing lists with one of her addresses. :

>>> from mailman.app.lifecycle import create_list   
>>> ant = create_list('ant@example.com')
>>> bee = create_list('bee@example.com')
>>> ant.subscribe(subscriber)
<Member: Elle Person <elle@example.com> on ant@example.com
         as MemberRole.member>
>>> bee.subscribe(subscriber)
<Member: Elle Person <elle@example.com> on bee@example.com
         as MemberRole.member>
>>> transaction.commit()

Elle can get her memberships for each of her email addresses. :

>>> dump_json('http://localhost:9001/3.0/addresses/'
...           'elle@example.com/memberships')
entry 0:
    address: http://localhost:9001/3.0/addresses/elle@example.com
    bounce_score: 0
    delivery_mode: regular
    display_name: Elle Person
    email: elle@example.com
    http_etag: "..."
    last_warning_sent: 0001-01-01T00:00:00
    list_id: ant.example.com
    member_id: 1
    role: member
    self_link: http://localhost:9001/3.0/members/1
    subscription_mode: as_address
    total_warnings_sent: 0
    user: http://localhost:9001/3.0/users/5
entry 1:
    address: http://localhost:9001/3.0/addresses/elle@example.com
    bounce_score: 0
    delivery_mode: regular
    display_name: Elle Person
    email: elle@example.com
    http_etag: "..."
    last_warning_sent: 0001-01-01T00:00:00
    list_id: bee.example.com
    member_id: 2
    role: member
    self_link: http://localhost:9001/3.0/members/2
    subscription_mode: as_address
    total_warnings_sent: 0
    user: http://localhost:9001/3.0/users/5
http_etag: "..."
start: 0
total_size: 2

>>> dump_json('http://localhost:9001/3.0/addresses/'
...           'eperson@example.com/memberships')
http_etag: "..."
start: 0
total_size: 0

When Elle subscribes to the bee list again with a different address, this does not show up in the list of memberships for his other address. :

>>> subscriber = user_manager.get_address('eperson@example.com')
>>> bee.subscribe(subscriber)
<Member: eperson@example.com on bee@example.com as MemberRole.member>
>>> transaction.commit()

>>> dump_json('http://localhost:9001/3.0/addresses/'
...           'elle@example.com/memberships')
entry 0:
    address: http://localhost:9001/3.0/addresses/elle@example.com
    bounce_score: 0
    delivery_mode: regular
    display_name: Elle Person
    email: elle@example.com
    http_etag: "..."
    last_warning_sent: 0001-01-01T00:00:00
    list_id: ant.example.com
    member_id: 1
    role: member
    self_link: http://localhost:9001/3.0/members/1
    subscription_mode: as_address
    total_warnings_sent: 0
    user: http://localhost:9001/3.0/users/5
entry 1:
    address: http://localhost:9001/3.0/addresses/elle@example.com
    bounce_score: 0
    delivery_mode: regular
    display_name: Elle Person
    email: elle@example.com
    http_etag: "..."
    last_warning_sent: 0001-01-01T00:00:00
    list_id: bee.example.com
    member_id: 2
    role: member
    self_link: http://localhost:9001/3.0/members/2
    subscription_mode: as_address
    total_warnings_sent: 0
    user: http://localhost:9001/3.0/users/5
http_etag: "..."
start: 0
total_size: 2

>>> dump_json('http://localhost:9001/3.0/addresses/'
...           'eperson@example.com/memberships')
entry 0:
    address: http://localhost:9001/3.0/addresses/eperson@example.com
    bounce_score: 0
    delivery_mode: regular
    display_name: Elle Person
    email: eperson@example.com
    http_etag: "..."
    last_warning_sent: 0001-01-01T00:00:00
    list_id: bee.example.com
    member_id: 3
    role: member
    self_link: http://localhost:9001/3.0/members/3
    subscription_mode: as_address
    total_warnings_sent: 0
    user: http://localhost:9001/3.0/users/5
http_etag: "..."
start: 0
total_size: 1

Deleting

Addresses can be deleted via the REST API. :

>>> fred = user_manager.create_address('fred@example.com', 'Fred Person')
>>> transaction.commit()
>>> dump_json('http://localhost:9001/3.0/addresses/fred@example.com')
display_name: Fred Person
email: fred@example.com
http_etag: "..."
original_email: fred@example.com
registered_on: 2005-08-01T07:49:23
self_link: http://localhost:9001/3.0/addresses/fred@example.com

>>> dump_json('http://localhost:9001/3.0/addresses/fred@example.com',
...     method='DELETE')
date: ...
server: ...
status: 204
>>> transaction.abort()

>>> print(user_manager.get_address('fred@example.com'))
None

If an address is linked to a user, deleting the address does not delete the user, it just unlinks it. :

>>> gwen = user_manager.create_user('gwen@example.com', 'Gwen Person')
>>> transaction.commit()
>>> dump_json('http://localhost:9001/3.0/users/6/addresses')
entry 0:
    display_name: Gwen Person
    email: gwen@example.com
    http_etag: "..."
    original_email: gwen@example.com
    registered_on: 2005-08-01T07:49:23
    self_link: http://localhost:9001/3.0/addresses/gwen@example.com
    user: http://localhost:9001/3.0/users/6
http_etag: "..."
start: 0
total_size: 1


>>> dump_json('http://localhost:9001/3.0/addresses/gwen@example.com',
...     method='DELETE')
date: ...
server: ...
status: 204

>>> dump_json('http://localhost:9001/3.0/users/6/addresses')
http_etag: "..."
start: 0
total_size: 0