timApp.messaging.messagelist package#

Submodules#

timApp.messaging.messagelist.emaillist module#

class timApp.messaging.messagelist.emaillist.MailmanConfig(MAILMAN_URL: str | None, MAILMAN_USER: str | None, MAILMAN_PASS: str | None, MAILMAN_UI_LINK_PREFIX: str | None)[source]#

Bases: object

MAILMAN_PASS: str | None#
MAILMAN_URL: str | None#
MAILMAN_USER: str | None#
timApp.messaging.messagelist.emaillist.add_email(mlist: mailmanclient.restobjects.mailinglist.MailingList, email: str, email_owner_pre_confirmation: bool, real_name: str | None, send_right: bool = True, delivery_right: bool = False) None[source]#

Add a new email to a email list.

Parameters
  • mlist – Email list where a new member is being added.

  • email – The email being added. Email address has to be validated before calling this function.

  • email_owner_pre_confirmation – Whether the email’s owner has to confirm them joining an email list. For True,

no confirmation is needed by the email’s owner. For False, Mailman send’s a confirmation mail for email’s owner to join the list. :param real_name: Name associated with the email. :param send_right: Whether email can send mail to the list. For True, then can send messages and for False they can’t. :param delivery_right: Whether email list delivers mail to email. For True, mail is delivered to email. For False, no mail is delivered.

timApp.messaging.messagelist.emaillist.check_mailman_connection() bool[source]#

Checks if the connection to Mailman is possible. Used for operations where the ability to connect to Mailman is optional, and other meaningful operations can resume in case the connection is not available.

Returns

True if connection is possible, i.e. _client is configured. Otherwise False.

timApp.messaging.messagelist.emaillist.create_new_email_list(list_options: timApp.messaging.messagelist.listinfo.ListInfo, owner: timApp.user.user.User) None[source]#

Create a new email list with proper initial options set.

Parameters
  • owner – Who owns this list.

  • list_options – Options for message lists, here we use the options necessary for email list creation.

Returns

timApp.messaging.messagelist.emaillist.delete_email_list(list_to_delete: mailmanclient.restobjects.mailinglist.MailingList, permanent_deletion: bool = False) None[source]#

Delete a mailing list.

Parameters
  • permanent_deletion – If True, then the list is permanently gone. If False, perform a soft deletion.

  • list_to_delete – MailingList object of the email list to be deleted.

timApp.messaging.messagelist.emaillist.find_members_for_address(address: str) dict[str, mailmanclient.restobjects.member.Member][source]#

Modified version of https://gitlab.com/mailman/mailmanclient/-/blob/509f19b3f666e54f460e7e5f7d2514c758111df3/src/mailmanclient/restobjects/user.py#L60 to find subscriptions for only the given address

timApp.messaging.messagelist.emaillist.freeze_list(mlist: mailmanclient.restobjects.mailinglist.MailingList) None[source]#

Freeze an email list. No posts are allowed on the list after freezing (owner might be an exception).

Think a course specific email list and the course ends, but mail archive is kept intact for later potential use. This stops (or at least mitigates) that the mail archive on that list changes after the freezing.

Parameters

mlist – The list about the be frozen.

timApp.messaging.messagelist.emaillist.get_domain_names() list[str][source]#

Returns a list of all domain names, that are configured for our instance of Mailman.

Returns

A list of possible domain names.

timApp.messaging.messagelist.emaillist.get_email_list_by_name(list_name: str, list_domain: str) mailmanclient.restobjects.mailinglist.MailingList[source]#

Get email list by name.

Parameters
  • list_name – List’s name.

  • list_domain – A domain we use to search an email list.

Returns

Return email list as an MailingList object.

timApp.messaging.messagelist.emaillist.get_email_list_member(mlist: mailmanclient.restobjects.mailinglist.MailingList, email: str) mailmanclient.restobjects.member.Member[source]#

Get a Member object with an email address from a MailingList object (i.e. from an email list).

Parameters
  • mlist – MailingList object, the email list in question.

  • email – Email used to find the member in an email list.

Returns

Return a Member object belonging to an email address on an email list.

Get a link for a list to use for advanced email list options and moderation.

The function assumes that Mailman uses Postorius as its web-UI. There exists no guarantee that other web-UIs would use the exact form for their links. If Postorius is changed to some other web-UI, this needs to be updated.

Parameters
  • listname – The list we are getting the UI link for.

  • domain – Domain for the list.

Returns

A Hyperlink for list web UI on the Mailman side. If there is no email list for (parameter domain is None)

then return None. Return None if no connection to Mailman is configured.

timApp.messaging.messagelist.emaillist.log_mailman(err: urllib.error.HTTPError, optional_message: str = '') None[source]#

Log potentially troublesome Mailman activity when mailmanclient raises HTTPErrors.

mailmanclient library raises liburl HTTPError messages for non 2xx status code responses for backward compatibility. Some of these indicate actual trouble that should be investigated, and some are just information about the operation (e.g. subscribe() method for MailinList objects raises HTTPError with a code 409 if the address we are trying to subscribe already exists on the list).

The general idea is to use log_error() for 5Xxx status codes and log_warning() for 4xx status codes. Technically 3xx codes should not happen for TIM, but they get log_info().

Parameters
  • err – The HTTPError to be logged.

  • optional_message – Optional, additional message for logging.

timApp.messaging.messagelist.emaillist.remove_email_list_membership(member: mailmanclient.restobjects.member.Member, permanent_deletion: bool = False) None[source]#

Remove membership from an email list.

Parameters
  • member – The membership to be terminated on a list.

  • permanent_deletion – If True, unsubscribes the user from the list permanently. If False, membership is

“deleted” in a soft manner by removing delivery and send rights, conforming to TIM’s policy in deleting objects. Membership is kept, but emails from member aren’t automatically let through nor does the member receive mail from the list.

timApp.messaging.messagelist.emaillist.set_default_templates(email_list: mailmanclient.restobjects.mailinglist.MailingList) None[source]#

Set default templates for email list.

Sometimes Mailman gets confused how mail is supposed to be interpreted, and with some email client’s different interpretation with Mailman’s email coding templates (e.g. list information footers) may appear as attachments. We fix it by setting header and footer for all new lists explicitly.

Param

email_list: The email list we are setting templates for.

timApp.messaging.messagelist.emaillist.set_email_list_allow_attachments(email_list: mailmanclient.restobjects.mailinglist.MailingList, allow_attachments_flag: bool) None[source]#

Set email list allowed attachments.

Parameters
  • email_list – The email list where allowed attachment extensions are set.

  • allow_attachments_flag – For True, set all the allowed extensions for an email list. If False, set the allowed extensions to an empty list.

timApp.messaging.messagelist.emaillist.set_email_list_allow_nonmember(email_list: mailmanclient.restobjects.mailinglist.MailingList, non_member_message_pass_flag: bool) None[source]#

Set email list’s non member (message pass) action.

Parameters
  • email_list – The email list where the non member message pass action is set.

  • non_member_message_pass_flag – For True, set the default non member moderation action as ‘accept’. For False,

set the default non member moderation action as ‘hold’

timApp.messaging.messagelist.emaillist.set_email_list_archive_policy(email_list: mailmanclient.restobjects.mailinglist.MailingList, archive: timApp.messaging.messagelist.listinfo.ArchiveType) None[source]#

Set email list’s archive policy.

Parameters
  • email_list – Email list

  • archive – What type of archiving is set for message list, and what that means for an email list.

timApp.messaging.messagelist.emaillist.set_email_list_default_reply_type(email_list: mailmanclient.restobjects.mailinglist.MailingList, default_reply_type: timApp.messaging.messagelist.listinfo.ReplyToListChanges) None[source]#

Set the email list’s default reply type, i.e. perform Reply-To munging.

Parameters
  • email_list – The email list where the reply type is set.

  • default_reply_type – See ReplyToListChanges and reply_to_munging variable.

timApp.messaging.messagelist.emaillist.set_email_list_description(mlist: mailmanclient.restobjects.mailinglist.MailingList, new_description: str) None[source]#

Set mailing list’s (short) description.

Parameters
  • mlist – Email list we wish to set description for.

  • new_description – A new (short) description for the email list.

timApp.messaging.messagelist.emaillist.set_email_list_info(mlist: mailmanclient.restobjects.mailinglist.MailingList, new_info: str) None[source]#

Set email list’s info, A.K.A. long description.

Parameters
  • mlist – Email list where the info is set.

  • new_info – New info for the email list.

timApp.messaging.messagelist.emaillist.set_email_list_member_delivery_status(member: mailmanclient.restobjects.member.Member, status: bool, by_moderator: bool = True) None[source]#

Change email list’s member’s delivery status on a list.

This function can fail if connection to Mailman is lost.

Parameters
  • member – Member who is having their delivery status changed.

  • status – If True, then this member receives email list’s messages. If false, member does not receive messages

from the email list. :param by_moderator: Who initiated the change in delivery right. If True, then the change was initiated by a moderator or owner of a list. If False, then the change was initiated by the member themselves.

timApp.messaging.messagelist.emaillist.set_email_list_member_send_status(member: mailmanclient.restobjects.member.Member, status: bool) None[source]#

Change user’s send status on an email list. Send right / status is changed by changing the member’s moderation status.

This function can fail if connection to Mailman is lost.

Parameters
  • member – Member who is having their send status changed.

  • status – A value that determines if option is ‘enabled’ or ‘disabled’. If True, the member can send messages

(past moderation) to the email list. If False, then all email from member will be rejected.

timApp.messaging.messagelist.emaillist.set_email_list_only_text(email_list: mailmanclient.restobjects.mailinglist.MailingList, only_text: bool) None[source]#

Set email list to only text mode. Affects new email sent to list and HyperKitty archived messages.

Parameters
  • email_list – Email list which is to be set into text only mode.

  • only_text – A boolean flag controlling list rendering mode. For True, the list is in an only text mode.

For False, the list is not on an only text mode, and other rendering (e.g. HTML) is allowed.

timApp.messaging.messagelist.emaillist.set_email_list_subject_prefix(email_list: mailmanclient.restobjects.mailinglist.MailingList, subject_prefix: str) None[source]#

Set the subject prefix for an email list.

Parameters
  • email_list – Email list where the subject prefix is to be set.

  • subject_prefix – The prefix set for email list’s subject.

timApp.messaging.messagelist.emaillist.set_email_list_unsubscription_policy(email_list: mailmanclient.restobjects.mailinglist.MailingList, can_unsubscribe_flag: bool) None[source]#

Set the unsubscription policy of an email list.

Parameters
  • email_list – The email list where the policy is to be set.

  • can_unsubscribe_flag – For True, then set the policy as ‘confirm_then_moderate’. For False, set the policy as

‘confirm’.

timApp.messaging.messagelist.emaillist.set_notify_owner_on_list_change(mlist: mailmanclient.restobjects.mailinglist.MailingList, on_change_flag: bool) None[source]#

Set email list’s notify owner on list change change flag.

Parameters
  • mlist – Email list where the flag is set.

  • on_change_flag – For True, set the notification flag on and then the changes on a list will send

notifications from Mailman. For False, set the flag off and then the email list will not send notifications from Mailman.

timApp.messaging.messagelist.emaillist.unfreeze_list(mlist: mailmanclient.restobjects.mailinglist.MailingList, msg_list: timApp.messaging.messagelist.messagelist_models.MessageListModel) None[source]#

The opposite of freezing a list.

Sets default values for delivery and send status of each member, depending on message lists options.

Parameters
  • msg_list – The message list the email list belongs to.

  • mlist – The list to bring back into function.

timApp.messaging.messagelist.emaillist.update_mailing_list_address(old: str, new: str) None[source]#
timApp.messaging.messagelist.emaillist.verify_emaillist_name_requirements(name_candidate: str, domain: str) None[source]#

Check email list’s name requirements. General message list name requirement checks are assumed to be passed at this point and that those requirements encompass email list name requirements.

Parameters
  • name_candidate – A possible name for an email list name to check.

  • domain – Domain where name availability is to be checked.

timApp.messaging.messagelist.emaillist.verify_mailman_connection() None[source]#

Verifies if the connection to Mailman is possible. Aborts if connection is not possible due to connection not being configured in the first place. Used for operations that are meaningless without configured connection to Mailman.

timApp.messaging.messagelist.emaillist.verify_name_availability(name_candidate: str, domain: str) None[source]#

Search for a name from the pool of used email list names.

Raises a RouteException if no connection was ever established with the Mailman server via mailmanclient.

Parameters
  • domain – Domain to search for lists, which then are used to check name availability.

  • name_candidate – The name to search for.

timApp.messaging.messagelist.emaillist.verify_reserved_names(name_candidate: str) None[source]#

Check a name candidate against reserved names, e.g. postmaster.

Raises a RouteException if the name candidate is a reserved name. If name is not reserved, the method completes silently.

If reserved names are not configured, we assume that there are no reserved names.

Parameters

name_candidate – The name to be compared against reserved names.

timApp.messaging.messagelist.listinfo module#

class timApp.messaging.messagelist.listinfo.ArchiveType(value)[source]#

Bases: enum.Enum

Different supported archive types.

GROUPONLY = 2#
NONE = 0#
PUBLIC = 4#
SECRET = 1#
UNLISTED = 3#
class timApp.messaging.messagelist.listinfo.Channel(value)[source]#

Bases: enum.Enum

The message channels TIM uses and provides for users or message lists.

EMAIL = 'email'#
EMAIL_LIST = 'email_list'#
TIM_MESSAGE = 'tim_message'#
class timApp.messaging.messagelist.listinfo.Distribution(tim_message: bool, email_list: bool)[source]#

Bases: object

A class to wrap information about the message channels used by a message list or TIM users.

email_list: bool#
tim_message: bool#
class timApp.messaging.messagelist.listinfo.GroupAndMembers(groupName: str, members: list[timApp.messaging.messagelist.listinfo.MemberInfo])[source]#

Bases: object

Helper class for querying user group and its members.

groupName: str#
members: list[timApp.messaging.messagelist.listinfo.MemberInfo]#
class timApp.messaging.messagelist.listinfo.ListInfo(name: str, archive: timApp.messaging.messagelist.listinfo.ArchiveType, default_reply_type: Optional[timApp.messaging.messagelist.listinfo.ReplyToListChanges] = None, notify_owners_on_list_change: Optional[bool] = None, only_text: Optional[bool] = None, list_description: Optional[str] = None, list_info: Optional[str] = None, email_admin_url: Optional[str] = None, tim_users_can_join: Optional[bool] = None, members_can_unsubscribe: Optional[bool] = None, default_send_right: Optional[bool] = None, default_delivery_right: Optional[bool] = None, list_subject_prefix: Optional[str] = None, domain: Optional[str] = None, non_member_message_pass: Optional[bool] = None, allow_attachments: Optional[bool] = None, distribution: Optional[timApp.messaging.messagelist.listinfo.Distribution] = None, removed: Optional[datetime.datetime] = None)[source]#

Bases: object

All options regarding message lists.

allow_attachments: bool | None = None#

A flag controlling if attachments are allowed on the list.

archive: timApp.messaging.messagelist.listinfo.ArchiveType#

The type of archive policy this list uses.

default_delivery_right: bool | None = None#

The list’s default delivery right for (new) members.

default_reply_type: timApp.messaging.messagelist.listinfo.ReplyToListChanges | None = None#

The default reply type of the list.

default_send_right: bool | None = None#

The list’s default send right for (new) members.

distribution: timApp.messaging.messagelist.listinfo.Distribution | None = None#

All the message channels the list is using.

domain: str | None = None#

The domain of the message list, if it has email list associated with it.

email_admin_url: str | None = None#

If the message list has an email list associated with it, this is the link to Mailman’s advanced list controls.

list_description: str | None = None#

A short description of the list and its purpose.

list_info: str | None = None#

Additional information about the list.

list_subject_prefix: str | None = None#

Messages routed by a message list will have this subject prefix added to them.

members_can_unsubscribe: bool | None = None#

Flag used to determine if the TIM members of this list can leave the list on their own.

name: str#

The name of the message list. A mandatory value when list options are considered.

non_member_message_pass: bool | None = None#

A flag that controls if messages from non members are automatically passed to the list.

notify_owners_on_list_change: bool | None = None#

A flag that determines if owners of the message list are notified of certain changes regarding the list, e.g. a new user joins the list.

only_text: bool | None = None#

If only pure text is allowed on a list.

removed: datetime.datetime | None = None#

If set, shows the date the message list is set to not be in use. If a user has access to the admin document even if this is set, it means that the message list is frozen, but not completely deleted.

tim_users_can_join: bool | None = None#

Flag used to determine if TIM users can directly join this list.

class timApp.messaging.messagelist.listinfo.MemberInfo(name: str, username: str, sendRight: bool, deliveryRight: bool, email: str, removed: Optional[datetime.datetime] = None)[source]#

Bases: object

Wrapper for information about a member on a message list.

deliveryRight: bool#
email: str#
name: str#
removed: datetime.datetime | None = None#
sendRight: bool#
username: str#
class timApp.messaging.messagelist.listinfo.ReplyToListChanges(value)[source]#

Bases: enum.Enum

Options for email list’s own address to be added to the Reply-To header for emails that are sent through the list. See reply_to_munging for mapping to Mailman’s options.

ADDLIST = 'point_to_list'#
NOCHANGES = 'no_munging'#

timApp.messaging.messagelist.mailman_events module#

class timApp.messaging.messagelist.mailman_events.MailmanMember(user_id: int, address: timApp.messaging.messagelist.mailman_events.MailmanMemberAddress)[source]#

Bases: object

address: timApp.messaging.messagelist.mailman_events.MailmanMemberAddress#
user_id: int#
class timApp.messaging.messagelist.mailman_events.MailmanMemberAddress(email: str, name: None | str)[source]#

Bases: object

email: str#
name: None | str#
class timApp.messaging.messagelist.mailman_events.MailmanMessageList(id: str, name: str, host: str)[source]#

Bases: object

host: str#
id: str#
name: str#
class timApp.messaging.messagelist.mailman_events.NewMessageEvent(event: str, mlist: timApp.messaging.messagelist.mailman_events.MailmanMessageList, message: dict)[source]#

Bases: object

event: str#
message: dict#
mlist: timApp.messaging.messagelist.mailman_events.MailmanMessageList#
class timApp.messaging.messagelist.mailman_events.SubscriptionEvent(event: str, mlist: timApp.messaging.messagelist.mailman_events.MailmanMessageList, member: timApp.messaging.messagelist.mailman_events.MailmanMember)[source]#

Bases: object

event: str#
member: timApp.messaging.messagelist.mailman_events.MailmanMember#
mlist: timApp.messaging.messagelist.mailman_events.MailmanMessageList#
timApp.messaging.messagelist.mailman_events.check_auth() bool[source]#
timApp.messaging.messagelist.mailman_events.handle_event() flask.wrappers.Response[source]#

Handle events sent by Mailman.

timApp.messaging.messagelist.mailman_events.handle_new_message(event: timApp.messaging.messagelist.mailman_events.NewMessageEvent) None[source]#

Handles an event raised by a new message.

Parameters

event – Contains information about a new message sent to Mailman’s list.

timApp.messaging.messagelist.mailman_events.has_valid_event_auth() bool[source]#

timApp.messaging.messagelist.messagelist_models module#

class timApp.messaging.messagelist.messagelist_models.MemberJoinMethod(value)[source]#

Bases: enum.Enum

How a user was added to a message list.

DIRECT_ADD = 1#

The owner of the list has just added this member. The member wasn’t asked. This is the only join method that makes sense for groups.

INVITED = 2#

User was invited and they confirmed joining.

JOINED = 3#

User joined the list on their own.

class timApp.messaging.messagelist.messagelist_models.MessageListDistribution(**kwargs)[source]#

Bases: sqlalchemy.ext.declarative.api.Model

Message list member’s chosen distribution channels.

channel#

Which message channels are used by a message list or a user.

id#
member#
message_list#
message_list_id#

Message list’s id, if this row is about message list’s channel distribution.

user_id#

Message list member’s id, if this row is about message list member’s channel distribution.

class timApp.messaging.messagelist.messagelist_models.MessageListExternalMember(**kwargs)[source]#

Bases: timApp.messaging.messagelist.messagelist_models.MessageListMember

A member of message list who is not a TIM user. Mainly intended for, but not necessary limited to, email-list only usage.

delivery_right#

If a member can get messages from a message list.

display_name#

Display name for external user, which in most cases should be the external member’s address’ owner’s name.

distribution#
email_address#

Email address of message list’s external member.

external_member#
get_email() str[source]#

Get message list’s external member’s email.

Returns

The email address.

get_name() str[source]#

Get the external member’s name, if one has been specified.

:return:The display name or an empty string.

get_username() str[source]#

External member’s don’t have usernames, but this is for consistency when using other methods.

id#
join_method#

How the member came to a list.

member#
member_type#

Discriminator for polymorhphic members.

membership_ended#

When member’s membership on a list ended. This is set when member is removed from a list. A value of None means the member is still on the list.

membership_verified#

When the user’s joining was verified. If user is added e.g. by a teacher to a course’s message list, this date is the date teacher added the member. If the member was invited, then this is the date they verified their join.

message_list#
message_list_id#

What message list a member belongs to.

send_right#

If a member can send messages to a message list.

tim_member#
user_info_json() dict[str, Any][source]#
class timApp.messaging.messagelist.messagelist_models.MessageListMember(**kwargs)[source]#

Bases: sqlalchemy.ext.declarative.api.Model

Database model for members of a message list.

delivery_right#

If a member can get messages from a message list.

distribution#
external_member#
get_email() str[source]#

The process of obtaining member’s address varies depending on if the member is a TIM user or not. Child classes have their own implementation depending on how they obtain the information. This is mostly for helping with types.

Returns

This particular instance raises NotImplementedError. The supposed return value is the user’s email

address.

id#
is_active() bool[source]#
Check if the message list’s member is an active member of the list. A member is an active member if they have

been verified and have not been removed from the list.

Returns

True if the member is both verified and not removed. Otherwise returns False.

is_external_member() bool[source]#

If this member is an external member to a message list.

is_group() bool[source]#

If this message list member is actually a group of users.

is_personal_user() bool[source]#

If this member is an individual user, i.e. a personal user group or an external member.

is_tim_member() bool[source]#

If this member is a ‘TIM member’, i.e. a user group. This can be either a personal user group or a group.

is_verified() bool[source]#

If the member is verified to be on the list.

join_method#

How the member came to a list.

member_type#

Discriminator for polymorhphic members.

membership_ended#

When member’s membership on a list ended. This is set when member is removed from a list. A value of None means the member is still on the list.

membership_verified#

When the user’s joining was verified. If user is added e.g. by a teacher to a course’s message list, this date is the date teacher added the member. If the member was invited, then this is the date they verified their join.

message_list#
message_list_id#

What message list a member belongs to.

remove(end_time: datetime.datetime | None = datetime.datetime(2022, 6, 18, 13, 8, 49, 981812, tzinfo=datetime.timezone.utc)) None[source]#

Shorthand for removing a member out of the group, by setting the membership_ended attribute.

send_right#

If a member can send messages to a message list.

tim_member#
to_json() dict[str, Any][source]#
user_info_json() dict[str, Any][source]#
class timApp.messaging.messagelist.messagelist_models.MessageListModel(**kwargs)[source]#

Bases: sqlalchemy.ext.declarative.api.Model

Database model for message lists

allow_attachments#

Flag if attachments are allowed on the list. The list of allowed attachment file extensions are stored at listoptions.py

archive#

The archive policy of a message list.

property archive_policy: timApp.messaging.messagelist.listinfo.ArchiveType#
block#

Relationship to the document that is used to manage this message list.

can_unsubscribe#

If a member can unsubscribe from this list on their own.

default_delivery_right#

Default delivery right for new members who join the list on their own.

default_reply_type#

Default reply type for the list.

default_send_right#

Default send right for new members who join the list on their own.

description#

A short description what a message list is about.

distribution#

The message channels the list uses.

property email_address: str | None#

Full email address of the messagelist, if the list has been assigned an active address. Otherwise None.

email_list_domain#

The domain used for an email list attached to a message list. If None/null, then message list doesn’t have an attached email list. This is a tad silly at this point in time, because JYU TIM only has one domain. However, this allows quick adaptation if more domains are added or otherwise changed in the future.

find_member(username: str | None, email: str | None) Optional[timApp.messaging.messagelist.messagelist_models.MessageListMember][source]#

Get member of this list. Member can be searched with username and/or email. At least one has to be given. If both are given, username is preferred and is used in a search first.

Raises ValueError if used with both name and email parameters as None.

Parameters
  • username – Userame of the member.

  • email – Member’s email address

Returns

A message list member, if one is found with given arguments. Otherwise return None.

static from_manage_doc_id(doc_id: int) timApp.messaging.messagelist.messagelist_models.MessageListModel[source]#
static from_name(name: str) timApp.messaging.messagelist.messagelist_models.MessageListModel[source]#

Gets a message list from name or throws a NotExist error if no unique list exists.

Parameters

name – The name of the list.

Returns

MessageListModel object, if a MessageListModel with attribute name is found.

static get_by_email(email: str) Optional[timApp.messaging.messagelist.messagelist_models.MessageListModel][source]#
static get_by_name(name_candidate: str) Optional[timApp.messaging.messagelist.messagelist_models.MessageListModel][source]#

Get a message list by its name, if a list with said name exists.

Parameters

name_candidate – The name of the message list.

Returns

Return the message list after query by name. Returns at most one result or None if no there are hits.

get_individual_members() list['MessageListMember'][source]#

Get all the members that are not groups.

Returns

A list of message list’s members, who are individual TIM users (MessageListTimMember objects) or

external members (MessageListExternalMember objects).

get_tim_members() list['MessageListTimMember'][source]#

Get all members that have belong to a user group, i.e. TIM users and user groups.

Returns

A list of MessageListTimMember objects.

id#
info#

Additional information about the message list.

mailman_list_id#
manage_doc_id#

The document which manages a message list.

members: list['MessageListTimMember']#

All the members of the list.

name#

The name of a message list.

static name_exists(name_candidate: str) bool[source]#

Check if given name already exists among message lists.

Parameters

name_candidate – The name we are checking if it already is already in use by another list.

non_member_message_pass#

Flag if non members messages to the list are passed straight through without moderation.

notify_owner_on_change#

Should the owner of the message list be notified if there are changes on message list members.

only_text#

Flag if only text format messages are allowed on a list.

removed#

When this list has been marked for removal.

subject_prefix#

What prefix message subjects that go through the list get.

tim_user_can_join#

Flag if TIM users can join the list on their own.

to_info() timApp.messaging.messagelist.listinfo.ListInfo[source]#
class timApp.messaging.messagelist.messagelist_models.MessageListTimMember(**kwargs)[source]#

Bases: timApp.messaging.messagelist.messagelist_models.MessageListMember

A member of message list who is also a TIM user(group). This can be one person in their own personal user group or this can be e.g. a course’s group.

delivery_right#

If a member can get messages from a message list.

distribution#
external_member#
get_email() str[source]#

Get TIM user group’s email. Email makes sense only for personal user groups. Using this method for groups returns an empty string

get_name() str[source]#

Get TIM user’s name. For group, this is an empty string. For a user, this is their full name.

get_username() str[source]#

Get the TIM user group’s name.

group_id#

A UserGroup id for a member.

id#
join_method#

How the member came to a list.

member#
member_type#

Discriminator for polymorhphic members.

membership_ended#

When member’s membership on a list ended. This is set when member is removed from a list. A value of None means the member is still on the list.

membership_verified#

When the user’s joining was verified. If user is added e.g. by a teacher to a course’s message list, this date is the date teacher added the member. If the member was invited, then this is the date they verified their join.

message_list#
message_list_id#

What message list a member belongs to.

send_right#

If a member can send messages to a message list.

tim_member#
user_group#
user_info_json() dict[str, Any][source]#

timApp.messaging.messagelist.messagelist_utils module#

class timApp.messaging.messagelist.messagelist_utils.BaseMessage(message_list_name: str, message_channel: timApp.messaging.messagelist.listinfo.Channel, sender: timApp.messaging.messagelist.messagelist_utils.EmailAndDisplayName, recipients: list[timApp.messaging.messagelist.messagelist_utils.EmailAndDisplayName], subject: str, message_body: str, domain: Optional[str] = None, reply_to: Optional[timApp.messaging.messagelist.messagelist_utils.EmailAndDisplayName] = None, timestamp: datetime.datetime = datetime.datetime(2022, 6, 18, 13, 8, 53, 174465, tzinfo=datetime.timezone.utc))[source]#

Bases: object

A unified datastructure for messages TIM handles.

domain: str | None = None#
message_body: str#
message_channel: timApp.messaging.messagelist.listinfo.Channel#
message_list_name: str#
recipients: list[timApp.messaging.messagelist.messagelist_utils.EmailAndDisplayName]#
reply_to: timApp.messaging.messagelist.messagelist_utils.EmailAndDisplayName | None = None#
sender: timApp.messaging.messagelist.messagelist_utils.EmailAndDisplayName#
subject: str#
timestamp: datetime.datetime = datetime.datetime(2022, 6, 18, 13, 8, 53, 174465, tzinfo=datetime.timezone.utc)#
class timApp.messaging.messagelist.messagelist_utils.EmailAndDisplayName(email: str, name: str)[source]#

Bases: object

Wrapper for parsed email messages containing sender/receiver email and display name.

email: str#
name: str#
to_json() dict[str, str][source]#
class timApp.messaging.messagelist.messagelist_utils.NameRequirements(value)[source]#

Bases: enum.Enum

An enumeration.

MIN_ONE_DIGIT = 5#
NAME_LENGTH_BOUNDED = 0#
NO_FORBIDDEN_CHARS = 4#
NO_SEQUENTIAL_DOTS = 2#
NO_TRAILING_DOTS = 3#
START_WITH_LOWERCASE = 1#
class timApp.messaging.messagelist.messagelist_utils.UserGroupDiff(add_user_ids: list[int], remove_user_ids: list[int])[source]#

Bases: object

add_user_ids: list[int]#
remove_user_ids: list[int]#
timApp.messaging.messagelist.messagelist_utils.add_message_list_external_email_member(msg_list: timApp.messaging.messagelist.messagelist_models.MessageListModel, external_email: str, send_right: bool, delivery_right: bool, em_list: mailmanclient.restobjects.mailinglist.MailingList, display_name: str | None) None[source]#
Add external member to a message list. External members at this moment only support external members to email

lists.

Parameters
  • msg_list – Message list where the member is to be added.

  • external_email – The email address of an external member to be added to the message list.

  • send_right – The send right to the list by the new member.

  • delivery_right – The delivery right to the list by the new member.

  • em_list – The email list where this external member will be also added, because at this time external members

only make sense for an email list. :param display_name: Optional name associated with the external member.

timApp.messaging.messagelist.messagelist_utils.add_new_message_list_group(msg_list: timApp.messaging.messagelist.messagelist_models.MessageListModel, ug: timApp.user.usergroup.UserGroup, send_right: bool, delivery_right: bool, em_list: mailmanclient.restobjects.mailinglist.MailingList | None) None[source]#

Add new (user) group to a message list.

For groups, checks that the adder has at least manage rights to group’s admin doc.

Performs a duplicate check for memberships. A duplicate member will not be added again to the list. The process of re-activating a removed member of a list is different. For re-activating an already existing member, use set_message_list_member_removed_status function.

This is a direct add, meaning member’s membership_verified attribute is set in this function. Use other means to invite members.

Parameters
  • msg_list – The message list where the group will be added.

  • ug – The user group being added to a message list.

  • send_right – Send right for user groups members, that will be added to the message list individually.

  • delivery_right – Delivery right for user groups members, that will be added to the message list individually.

  • em_list – An optional email list. If given, then all the members of the user group will also be subscribed to

the email list.

timApp.messaging.messagelist.messagelist_utils.archive_message(message_list: timApp.messaging.messagelist.messagelist_models.MessageListModel, message: timApp.messaging.messagelist.messagelist_utils.BaseMessage) None[source]#

Archive a message for a message list.

Parameters
  • message_list – The message list where the archived message belongs.

  • message – The message being archived.

timApp.messaging.messagelist.messagelist_utils.check_archives_folder_exists(message_list: timApp.messaging.messagelist.messagelist_models.MessageListModel) timApp.folder.folder.Folder | None[source]#

Ensures archive folder exists for the given list if the list is archived.

Parameters

message_list – Message list to check

Returns

The archive folder for the list if the list should be archived. Otherwise None.

timApp.messaging.messagelist.messagelist_utils.check_name_rules(name_candidate: str) Iterator[timApp.messaging.messagelist.messagelist_utils.NameRequirements][source]#

Check if name candidate complies with naming rules.

Parameters

name_candidate – What name we are checking against the rules.

Returns

A generator that returns violated name rules.

timApp.messaging.messagelist.messagelist_utils.create_archive_doc_with_permission(archive_subject: str, archive_doc_path: str, message_list: timApp.messaging.messagelist.messagelist_models.MessageListModel, message: timApp.messaging.messagelist.messagelist_utils.BaseMessage) timApp.document.docentry.DocEntry[source]#

Create archive document with permissions matching the message list’s archive policy.

Parameters
  • archive_subject – The subject of the archive document.

  • archive_doc_path – The path where the archive document should be created.

  • message_list – The message list where the message belongs.

  • message – The message about to be archived.

Returns

The archive document.

timApp.messaging.messagelist.messagelist_utils.create_management_doc(msg_list_model: timApp.messaging.messagelist.messagelist_models.MessageListModel, list_options: timApp.messaging.messagelist.listinfo.ListInfo) timApp.document.docinfo.DocInfo[source]#

Create management doc for a new message list.

Parameters
  • msg_list_model – The message list the management document is created for.

  • list_options – Options for creating the management document.

Returns

Newly created management document.

timApp.messaging.messagelist.messagelist_utils.get_message_list_owners(mlist: timApp.messaging.messagelist.messagelist_models.MessageListModel) list[timApp.user.usergroup.UserGroup][source]#

Get the owners of a message list.

Parameters

mlist – The message list we want to know the owners.

Returns

A list of owners, as their personal user group.

timApp.messaging.messagelist.messagelist_utils.message_body_to_md(body: str) str[source]#

Converts mail body into markdown. Importantly, the function

  • adds extra spacing for quotes

  • adds explicit newline to non-paragraph breaks

  • makes links clickable

  • cleans up Outlook safelinks

Parameters

body – Original message body.

Returns

Markdown-converted message body.

timApp.messaging.messagelist.messagelist_utils.new_list(list_options: timApp.messaging.messagelist.listinfo.ListInfo) tuple[timApp.document.docinfo.DocInfo, timApp.messaging.messagelist.messagelist_models.MessageListModel][source]#

Adds a new message list into the database and creates the list’s management doc.

Parameters

list_options – The list information for creating a new message list. Used to carry list’s name and archive

policy. :return: The management document of the message list. :return: The message list db model.

timApp.messaging.messagelist.messagelist_utils.parse_mailman_message(original: dict, msg_list: timApp.messaging.messagelist.messagelist_models.MessageListModel) timApp.messaging.messagelist.messagelist_utils.BaseMessage[source]#

Modify an email message sent from Mailman to TIM’s universal message format.

Parameters
  • original – An email message sent from Mailman.

  • msg_list – The message list where original is meant to go.

Returns

A BaseMessage object corresponding the original email message.

timApp.messaging.messagelist.messagelist_utils.parse_mailman_message_address(original: dict, header: str) list[timApp.messaging.messagelist.messagelist_utils.EmailAndDisplayName] | None[source]#

Parse (potentially existing) fields ‘from’ ‘to’, ‘cc’, or ‘bcc’ from a dict representing Mailman’s email message. The fields are in lists, with individual list indicies being lists themselves of the form

[‘Display Name’, ‘email@domain.fi’]

Parameters
  • original – Original message.

  • header – One of “from”, “to”, “cc” or “bcc”.

Returns

Return None if the header is not one of “from”, “to”, “cc” or “bcc”. Otherwise return a list of

EmailAndDisplayName objects.

timApp.messaging.messagelist.messagelist_utils.set_member_send_delivery(member: timApp.messaging.messagelist.messagelist_models.MessageListMember, send: bool, delivery: bool, email_list: Optional[mailmanclient.restobjects.mailinglist.MailingList] = None) None[source]#

Set message list member’s send and delivery rights.

Parameters
  • member – Member who’s rights are being set.

  • send – Member’s new send right.

  • delivery – Member’s new delivery right.

  • email_list – If the message list has email list as one of its message channels, set the send and delivery rights there also.

Returns

None.

timApp.messaging.messagelist.messagelist_utils.set_message_list_allow_attachments(message_list: timApp.messaging.messagelist.messagelist_models.MessageListModel, allow_attachments_flag: bool | None) None[source]#

Set the flag controlling if a message list accepts messages with attachments.

Parameters
  • message_list – The message list where the flag is to be set.

  • allow_attachments_flag – An optional boolean flag. For True, the list will allow a pre-determined set of

attachments. For False, no attachments are allowed. For None, the current value is kept.

timApp.messaging.messagelist.messagelist_utils.set_message_list_default_delivery_right(message_list: timApp.messaging.messagelist.messagelist_models.MessageListModel, default_delivery_right_flag: bool | None) None[source]#

Set the message list new member default delivery right.

Parameters
  • message_list – The message list where the flag is set.

  • default_delivery_right_flag – An optional boolean flag. For True, new members on the list get default delivery

right. For False, new members don’t automatically get a delivery right. For None, the current value is kept.

timApp.messaging.messagelist.messagelist_utils.set_message_list_default_reply_type(message_list: timApp.messaging.messagelist.messagelist_models.MessageListModel, default_reply_type: timApp.messaging.messagelist.listinfo.ReplyToListChanges | None) None[source]#

Set a value controlling how replies to a message list are steered.

The reply type is analogous to email lists’ operation of “Reply-To munging”. Reply-To munging is a process where messages sent to list may be subject to having their Reply-To header changed from what the sender of the message initially used. This is mainly used (and sometimes abused) to steer conversation from announce-only lists (which don’t accept posts from anyone except few select individuals) to separate discussion lists.

Parameters
  • message_list – The message list where the value is to be set.

  • default_reply_type – An optional enumeration. For value NOCHANGES the user is completely left the control

how to respond to messages sent from the list. For value ADDLIST the replies will be primarily steered towards the message list. For None, the current value is kept.

timApp.messaging.messagelist.messagelist_utils.set_message_list_default_send_right(message_list: timApp.messaging.messagelist.messagelist_models.MessageListModel, default_send_right_flag: bool | None) None[source]#

Set the default message list new member send right flag.

Parameters
  • message_list – The message list where the flag is set.

  • default_send_right_flag – An optional boolean flag. For True, new members on the list get default send right.

For False, new members don’t get a send right. For None, the current value is kept.

timApp.messaging.messagelist.messagelist_utils.set_message_list_description(message_list: timApp.messaging.messagelist.messagelist_models.MessageListModel, description: str | None) None[source]#

Set a (short) description to a message list and its associated message channels.

Parameters
  • message_list – The message list where the description is set.

  • description – The new description. If None, keep the current value.

timApp.messaging.messagelist.messagelist_utils.set_message_list_info(message_list: timApp.messaging.messagelist.messagelist_models.MessageListModel, info: str | None) None[source]#

Set a long description (called ‘info’ on Mailman) to a message list and its associated message channels.

Parameters
  • message_list – The message list where the (long) description is set.

  • info – The new long description. If None, keep the current value.

timApp.messaging.messagelist.messagelist_utils.set_message_list_member_can_unsubscribe(message_list: timApp.messaging.messagelist.messagelist_models.MessageListModel, can_unsubscribe_flag: bool | None) None[source]#

Set the list member’s free unsubscription flag, and propagate that setting to channels that have own handling of unsubscription.

If the message list has an email list as a message channel, this will set the equilavent flag on the email list.

Parameters
  • message_list – Message list where the flag is being set.

  • can_unsubscribe_flag – An optional boolean flag. For True, the member can unsubscribe on their own. For False, then the member can’t unsubscribe from the list on their own. If None, then the current value is kept.

timApp.messaging.messagelist.messagelist_utils.set_message_list_member_removed_status(member: timApp.messaging.messagelist.messagelist_models.MessageListMember, removed: datetime.datetime | None, email_list: mailmanclient.restobjects.mailinglist.MailingList | None) None[source]#

Set the message list member’s membership removed status.

Parameters
  • member – The member who’s membership status is being set.

  • removed – Member’s date of removal from the message list. If None, then the member is an active member on the

list. :param email_list: An email list belonging to the message list. If None, the message list does not have an email list.

timApp.messaging.messagelist.messagelist_utils.set_message_list_non_member_message_pass(message_list: timApp.messaging.messagelist.messagelist_models.MessageListModel, non_member_message_pass_flag: bool | None) None[source]#

Set message list’s non member message pass flag.

Parameters
  • message_list – The message list where the flag is set.

  • non_member_message_pass_flag – An optional boolean flag. For True, sources outside the list can send messages

to this list. If False, messages form sources outside the list will be hold for moderation. For None, the current value is kept.

timApp.messaging.messagelist.messagelist_utils.set_message_list_notify_owner_on_change(message_list: timApp.messaging.messagelist.messagelist_models.MessageListModel, notify_owners_on_list_change_flag: bool | None) None[source]#

Set the notify list owner on list change flag for a list, and update necessary channels with this information.

If the message list has an email list as a message channel, this will set the equilavent flag on the email list.

Parameters
  • message_list – The message list where the flag is being set.

  • notify_owners_on_list_change_flag – An optional boolean flag. If True, then changes on the message list sends

notifications to list owners. If False, notifications won’t be sent. If None, nothing is set.

timApp.messaging.messagelist.messagelist_utils.set_message_list_only_text(message_list: timApp.messaging.messagelist.messagelist_models.MessageListModel, only_text: bool | None) None[source]#

Set the flag controlling if message list is to accept text-only messages.

Parameters
  • message_list – The message list where the flag is to be set.

  • only_text – An optional boolean flag. For True, the message list is set to text-only mode. For False, the

message list accepts HTML-based messages. For None, the current value is kept.

timApp.messaging.messagelist.messagelist_utils.set_message_list_subject_prefix(message_list: timApp.messaging.messagelist.messagelist_models.MessageListModel, subject_prefix: str | None) None[source]#

Set the message list’s subject prefix.

If the message list has an email list as a message list, then set the subject prefix there also.

Sets one extra space automatically to offset prefix from the actual title.

Parameters
  • message_list – The message list where the subject prefix is being set.

  • subject_prefix – The prefix set for messages that go through the list. If None, then the current value is

kept.

timApp.messaging.messagelist.messagelist_utils.set_message_list_tim_users_can_join(message_list: timApp.messaging.messagelist.messagelist_models.MessageListModel, can_join_flag: bool | None) None[source]#

Set the flag controlling if TIM users can directly join this list.

Because the behaviour that is controlled by the can_join_flag applies to TIM users, there is no message channel specific handling.

Parameters
  • message_list – Message list where the flag is being set.

  • can_join_flag – An optional boolean flag. If True, then TIM users can directly join this list, no moderation

needed. If False, then TIM users can’t direclty join the message list. If None, the current value is kept.

timApp.messaging.messagelist.messagelist_utils.sync_message_list_on_add(user: timApp.user.user.User, new_group: timApp.user.usergroup.UserGroup) None[source]#

On adding a user to a new group, sync the user to user group’s message lists.

Parameters
  • user – The user that was added to the new_group.

  • new_group – The new group that the user was added to.

timApp.messaging.messagelist.messagelist_utils.sync_message_list_on_expire(user: timApp.user.user.User, old_group: timApp.user.usergroup.UserGroup) None[source]#

On removing a user from a user group, remove the user from all the message lists that watch the group.

Parameters
  • user – The user who was removed from the user group.

  • old_group – The group where the user was removed from.

timApp.messaging.messagelist.messagelist_utils.sync_usergroup_messagelist_members(diffs: dict[int, timApp.messaging.messagelist.messagelist_utils.UserGroupDiff], permanent_delete: bool = False) None[source]#
timApp.messaging.messagelist.messagelist_utils.verify_can_create_lists() None[source]#
timApp.messaging.messagelist.messagelist_utils.verify_messagelist_name_requirements(name_candidate: str) None[source]#

Checks name requirements specific for email list.

If at any point a name requirement check fails, then an exception is raised an carried to the client. If all name requirements are met, then succeed silently.

Parameters

name_candidate – Name to check against naming rules.

timApp.messaging.messagelist.messagelist_utils.verify_name_availability(name_candidate: str) None[source]#

Check if a message list with a given name already exists.

Parameters

name_candidate – The name to be checked if it already exists.

timApp.messaging.messagelist.messagelist_utils.verify_name_rules(name_candidate: str) None[source]#

Check if name candidate complies with naming rules.

The function raises a RouteException if naming rule is violated. If this function doesn’t raise an exception, then the name candidate follows naming rules.

Parameters

name_candidate – What name we are checking against the rules.

timApp.messaging.messagelist.routes module#

class timApp.messaging.messagelist.routes.ArchivedMessage(anchor: str, title: str, date: str, recipients: list[str], sender: str, body: str)[source]#

Bases: object

anchor: str#
body: str#
date: str#
recipients: list[str]#
sender: str#
title: str#
timApp.messaging.messagelist.routes.add_member(member_candidates: list[str], msg_list: str, send_right: bool, delivery_right: bool) flask.wrappers.Response[source]#

Add new members to a message list.

Parameters
  • member_candidates – Names of member candidates.

  • msg_list – The message list where we are trying to add new members.

  • send_right – The send right on a list for all the member candidates.

  • delivery_right – The delivery right on a list for all the member candidates.

Returns

OK response.

timApp.messaging.messagelist.routes.check_name(name: str) flask.wrappers.Response[source]#
timApp.messaging.messagelist.routes.create_list(options: timApp.messaging.messagelist.listinfo.ListInfo) flask.wrappers.Response[source]#

Handles creating a new message list.

:param options All options necessary for establishing a new message list. :return: A Response with the list’s management doc included. This way the creator can re-directed to the list’s management page directly.

timApp.messaging.messagelist.routes.delete_list(listname: str, permanent: bool) flask.wrappers.Response[source]#

Delete message and associated message channels.

Parameters
  • listname – The list to be deleted.

  • permanent – A boolean flag indicating if the deletion is meant to be permanent.

Returns

A string describing how the operation went.

timApp.messaging.messagelist.routes.domains() flask.wrappers.Response[source]#

Send possible domains for a client, if such exists.

Returns

If domains are configured, return them as an array.

timApp.messaging.messagelist.routes.export_archive(list_name: str) flask.wrappers.Response | str[source]#

Export the archive as a simple HTML file.

timApp.messaging.messagelist.routes.get_group_members(list_name: str) flask.wrappers.Response[source]#

View function for getting members of groups that are on a message list.

Parameters

list_name – Message list.

Returns

All members of groups associated in a message list as a list of GroupAndMembers objects.

timApp.messaging.messagelist.routes.get_list(listname: str) flask.wrappers.Response[source]#

Get the information for a message list.

Parameters

listname – Name of the list

Returns

ListOptions with the list’s information.

timApp.messaging.messagelist.routes.get_members(list_name: str) flask.wrappers.Response[source]#

Get members belonging to a certain list.

Parameters

list_name – The list where we are querying all the members.

Returns

All the members of a list.

timApp.messaging.messagelist.routes.get_sibling_archive_messages(message_doc_id: int) flask.wrappers.Response[source]#
timApp.messaging.messagelist.routes.parse_external_member(external_member_candidate: str) list[str] | None[source]#

Parse the information of an external member.

There are two supported ways to give external members. The user can write

user.userington@domain.fi User Userington

or

User Userington <user.userington@domain.fi>

Parameters

external_member_candidate – A string represeting the external member.

Returns

Return a list of the form [email, name_part_1, name_part_2, …] if parsing was successful. Otherwise

return None.

timApp.messaging.messagelist.routes.save_list_options(options: timApp.messaging.messagelist.listinfo.ListInfo) flask.wrappers.Response[source]#

Save message list’s options.

Parameters

options – The options to be saved.

Returns

OK response.

timApp.messaging.messagelist.routes.save_members(listname: str, members: list[timApp.messaging.messagelist.listinfo.MemberInfo]) flask.wrappers.Response[source]#

Save the state of existing list members, e.g. send and delivery rights.

Parameters
  • listname – The name of the message list where the members will be saved.

  • members – The members to be saved.

Returns

Response for the client. The Response is a simple ok_response().

timApp.messaging.messagelist.routes.test_name(name_candidate: str) None[source]#

Check new message list’s name candidate’s name.

The name has to meet naming rules, it has to be not already be in use and it cannot be a reserved name. If the function retuns control to its caller, then name is viable to use for a message list. If at some point the name is not viable, then an exception is raised.

Parameters

name_candidate – The name candidate to check.

Module contents#