pycroft.lib

pycroft.lib.address

get_or_create_address(street: str, number: str, addition: str | None, zip_code: str, city: str | None = None, state: str | None = None, country: str | None = None) Address[source]

Returns an existing address or creates a new one.

If the address is to be used for some other update operation, make sure to wrap this call and the next one in a Session.no_autoflush block, because else the address cleanup trigger may fire.

pycroft.lib.exc

exception PycroftLibException[source]

pycroft.lib.facilities

exception RoomAlreadyExistsException[source]
get_overcrowded_rooms(building_id: int = None) dict[int, list[User]][source]
Parameters

building_id – Limit to rooms of the building. Returns a dict of overcrowded rooms with their inhabitants.

Returns

a dict mapping room ids to inhabitants

similar_rooms_query(number: str, level: int, building: Building, vo_suchname: str | None = None) Select[source]
create_room(building: Building, level: int, number: str, processor: User, address: Address, inhabitable: bool = True, vo_suchname: str | None = None) Room[source]
edit_room(room: Room, number: str, inhabitable: bool, vo_suchname: str, address: Address, processor: User) Room[source]
get_room(building_id: int, level: int, room_number: str) Room | None[source]
class RoomAddressSuggestion(street: str, number: str, zip_code: str, city: str, state: str, country: str)[source]
street: str
number: str
zip_code: str
city: str
state: str
country: str
suggest_room_address_data(building: Building) RoomAddressSuggestion | None[source]

Return the most common address features of preexisting rooms in a certain building.

sort_buildings(buildings: Iterable[Building]) list[Building][source]
determine_building(shortname: str | None = None, id: int | None = None) Building | None[source]

Determine building from shortname or id in this order.

Parameters
  • shortname – The short name of the building

  • id – The id of the building

Returns

The unique building

pycroft.lib.finance

user_has_paid(user: User) bool[source]
get_typed_splits(splits: Sequence[Split]) Iterable[tuple[Split, Split]][source]
get_transaction_type(transaction: Transaction) tuple[str, str] | None[source]
get_last_import_date(session: Session) datetime | None[source]
import_newer_than_days(session: Session, days: int) bool | None[source]
get_system_accounts(session: Session) list[Account][source]

Return all accounts which neither belong to a user nor are user assets

get_accounts_by_type(session: Session) dict[Literal['ASSET', 'USER_ASSET', 'BANK_ASSET', 'LIABILITY', 'EXPENSE', 'REVENUE'] | Literal['LEGACY'], list[Account]][source]
get_all_bank_accounts(session: Session) list[BankAccount][source]
get_unassigned_bank_account_activities(session: Session) list[BankAccountActivity][source]
get_all_mt940_errors(session: Session) list[MT940Error][source]

pycroft.lib.host

change_mac(interface: Interface, mac: str, processor: User) Interface[source]

This method will change the mac address of the given interface to the new mac address.

Parameters
  • interface – the interface which should become a new mac address.

  • mac – the new mac address.

  • processor – the user who initiated the mac address change.

Returns

the changed interface with the new mac address.

generate_hostname(ip_address: IPAddress) str[source]
host_create(owner: User, room: Room, name: str, processor: User) Host[source]
host_edit(host: Host, owner: User, room: Room, name: str, processor: User) None[source]
migrate_host(session: Session, host: Host, new_room: Room, processor: User) None[source]

Migrate a Host to a new room and if necessary to a new subnet. If the host changes subnet, it will get a new IP address.

Parameters
  • host – Host to be migrated

  • new_room – new room of the host

  • processor – User processing the migration

Returns

host_delete(host: Host, processor: User) None[source]
interface_create(host: Host, name: str, mac: str, ips: Iterable[IPAddress] | None, processor: User) Interface[source]
interface_edit(interface: Interface, name: str, mac: str, ips: Iterable[IPAddress], processor: User) None[source]
interface_delete(interface: Interface, processor: User) None[source]
sort_ports(ports: Iterable) list[TPort][source]
get_conflicting_interface(session: Session, new_mac: str, current_mac: str | None = None) Interface | None[source]
setup_ipv4_networking(session: Session, host: Host) None[source]

Add suitable ips for every interface of a host

pycroft.lib.infrastructure

exception PatchPortAlreadyPatchedException[source]
exception PatchPortAlreadyExistsException[source]
create_patch_port(name: str, room: Room, switch_room: Room, processor: User) PatchPort[source]
edit_patch_port(patch_port: PatchPort, name: str, room: Room, processor: User) None[source]
delete_patch_port(patch_port: PatchPort, processor: User) None[source]
patch_switch_port_to_patch_port(switch_port: SwitchPort, patch_port: PatchPort, processor: User) None[source]
remove_patch_to_patch_port(patch_port: PatchPort, processor: User) None[source]
create_switch_port(switch: Switch, name: str, default_vlans: Iterable[VLAN], processor: User) SwitchPort[source]
edit_switch_port(switch_port: SwitchPort, name: str, default_vlans: Iterable[VLAN], processor: User) None[source]
delete_switch_port(switch_port: SwitchPort, processor: User) None[source]
edit_switch(session: Session, switch: Switch, name: str, management_ip: str, room: Room, processor: User) None[source]
create_switch(session: Session, name: str, management_ip: IPAddress, room: Room, processor: User) Switch[source]
delete_switch(session: Session, switch: Switch, processor: User) None[source]

pycroft.lib.logging

log_event(message: str, author: User, created_at: datetime | None = None) LogEntry[source]

This method will create a new LogEntry.

Parameters
  • message – the log message text

  • author – user responsible for the entry

  • created_at – Creation time of the entry. Defaults to current database time if None.

Returns

the newly created RoomLogEntry.

log_task_event(message: str, author: User, task: Task, created_at: datetime | None = None) TaskLogEntry[source]

This method will create a new TaskLogEntry.

Parameters
  • message – the log message text

  • author – user responsible for the entry

  • task – the task for which the log should be created

  • created_at – Creation time of the entry. Defaults to current database time if None.

Returns

the newly created UserLogEntry.

log_user_event(message: str, author: User, user: User, created_at: datetime | None = None) UserLogEntry[source]

This method will create a new UserLogEntry.

Parameters
  • message – the log message text

  • author – user responsible for the entry

  • user – the user for which the log should be created

  • created_at – Creation time of the entry. Defaults to current database time if None.

Returns

the newly created UserLogEntry.

log_room_event(message: str, author: User, room: Room, created_at: datetime | None = None) RoomLogEntry[source]

This method will create a new RoomLogEntry.

Parameters
  • message – the log message text

  • author – user responsible for the entry

  • room – the room for which the log should be created

  • created_at – Creation time of the entry. Defaults to current database time if None.

Returns

the newly created RoomLogEntry.

pycroft.lib.mail

class Mail(to_name: 'str', to_address: 'str', subject: 'str', body_plain: 'str', body_html: 'str | None' = None, reply_to: 'str | None' = None)[source]
to_name: str
to_address: str
subject: str
body_plain: str
body_html: str | None = None
reply_to: str | None = None
property body_plain_mime: MIMEText
property body_html_mime: MIMEText | None
class MailTemplate(**kwargs: Any)[source]
template: str
subject: str
args: dict
render(**kwargs: Any) tuple[str, str][source]
property jinja_template: Template
compose_mail(mail: Mail, from_: str, default_reply_to: str | None) MIMEMultipart[source]
exception RetryableException[source]
send_mails(mails: list[Mail]) tuple[bool, int][source]

Send MIME text mails

Returns False, if sending fails. Else returns True.

Parameters

mails – A list of mails

Returns

Whether the transmission succeeded

Context

config

class UserConfirmEmailTemplate(**kwargs: Any)[source]
template: str = 'user_confirm_email.html'
subject: str = 'Bitte bestätige deine E-Mail Adresse // Please confirm your email address'
class UserResetPasswordTemplate(**kwargs: Any)[source]
template: str = 'user_reset_password.html'
subject: str = 'Neues Passwort setzen // Set a new password'
class UserMovedInTemplate(**kwargs: Any)[source]
template: str = 'user_moved_in.html'
subject: str = 'Wohnortänderung // Change of residence'
class UserCreatedTemplate(**kwargs: Any)[source]
template: str = 'user_created.html'
subject: str = 'Willkommen bei der AG DSN // Welcome to the AG DSN'
class MemberRequestPendingTemplate(**kwargs: Any)[source]
template: str = 'member_request_pending.html'
subject: str = 'Deine Mitgliedschaftsanfrage // Your member request'
class MemberRequestDeniedTemplate(**kwargs: Any)[source]
template: str = 'member_request_denied.html'
subject: str = 'Mitgliedschaftsanfrage abgelehnt // Member request denied'
class MemberRequestMergedTemplate(**kwargs: Any)[source]
template: str = 'member_request_merged.html'
subject: str = 'Mitgliedskonto zusammengeführt // Member account merged'
class TaskFailedTemplate(**kwargs: Any)[source]
template: str = 'task_failed.html'
subject: str = 'Aufgabe fehlgeschlagen // Task failed'
class MemberNegativeBalance(**kwargs: Any)[source]
template: str = 'member_negative_balance.html'
subject: str = 'Deine ausstehenden Zahlungen // Your due payments'
send_template_mails(email_addresses: list[str], template: MailTemplate, **kwargs: Any) None[source]
class MailConfig(mail_envelope_from: 'str', mail_from: 'str', mail_reply_to: 'str | None', smtp_host: 'str', smtp_user: 'str', smtp_password: 'str', smtp_port: 'int' = 465, smtp_ssl: 'str' = 'ssl', template_path_type: 'InitVar[str | None]' = None, template_path: 'InitVar[str | None]' = None)[source]
mail_envelope_from: str
mail_from: str
mail_reply_to: str | None
smtp_host: str
smtp_user: str
smtp_password: str
smtp_port: int = 465
smtp_ssl: str = 'ssl'
template_path_type: dataclasses.InitVar[str | None] = None
template_path: dataclasses.InitVar[str | None] = None
template_env: Environment
classmethod from_env() Self[source]

pycroft.lib.membership

This module contains functions concerning groups, membership, and property management.

known_properties() set[str][source]

Return a set of all known properties, granted or denied.

grant_property(group: PropertyGroup, name: str) Property[source]

Grants a property to a group.

Parameters
  • group – a group

  • name – the name of the property

Returns

created or changed property object

deny_property(group: PropertyGroup, name: str) Property[source]

Denies a property to a group.

Parameters
  • group – a group

  • name – the name of the property

Returns

created or changed property object

remove_property(group: PropertyGroup, name: str) None[source]

Removes a property association (grant or denial) with a given group.

Parameters
  • group – a group

  • name – the name of the property

Raises

ValueError – if group doesn’t have a property with the given name

make_member_of(user: User, group: PropertyGroup, processor: User, during: Interval[DateTimeTz] = ((pycroft.helpers.interval.NegativeInfinity, False), (pycroft.helpers.interval.PositiveInfinity, False))) None[source]

Makes a user member of a group in a given interval.

If the given interval overlaps with an existing membership, this method will join the overlapping intervals together, so that there will be at most one membership for particular user in particular group at any given point in time.

Parameters
  • user – the user

  • group – the group

  • processor – User issuing the addition

  • during

remove_member_of(user: User, group: PropertyGroup, processor: User, during: Interval[DateTimeTz] = ((pycroft.helpers.interval.NegativeInfinity, False), (pycroft.helpers.interval.PositiveInfinity, False))) None[source]

Remove a user from a group in a given interval.

The interval defaults to the unbounded interval, so that the user will be removed from the group at any point in time, removing all memberships in this group retroactively.

However, a common use case is terminating a membership by setting during=starting_from(now).

Parameters
  • user – the user

  • group – the group

  • processor – User issuing the removal

  • during

edit_property_group(group: PropertyGroup, name: str, permission_level: int, processor: User) None[source]
delete_property_group(group: PropertyGroup, processor: User) None[source]
user_memberships_query(user_id: int, active_groups_only: bool = False) Result[tuple[Membership, list[str], list[str]]][source]
change_membership_active_during(session: Session, membership_id: int, begins_at: DateTimeTz, ends_at: DateTimeTz | None, processor: User) None[source]

modify the active_during field of a membership

pycroft.lib.net

exception SubnetFullException[source]
exception MacExistsException[source]
get_free_ip(subnets: Iterable[Subnet]) tuple[IPAddress, Subnet][source]
get_subnets_for_room(room: Room) list[Subnet][source]
calculate_max_ips(subnet: Subnet) int[source]
namedtuple SubnetUsage(max_ips, used_ips)[source]

SubnetUsage(max_ips, used_ips)

Fields
  1.  max_ips (int) – Alias for field number 0

  2.  used_ips (int) – Alias for field number 1

property free_ips: int
get_subnets_with_usage() list[tuple[Subnet, SubnetUsage]][source]
delete_ip(session: Session, ip: IPAddress) None[source]
user_search_query(user_id: int | None = None, name: str | None = None, login: str | None = None, mac: str | None = None, ip_address: str | None = None, property_group_id: int | None = None, building_id: int | None = None, email: str | None = None, person_id: int | None = None, query: str | None = None) Query[source]

pycroft.lib.stats

class OverviewStats(member_requests: int, users_in_db: int, members: int, not_paid_all: int, not_paid_members: int)[source]
member_requests: int
users_in_db: int
members: int
not_paid_all: int
not_paid_members: int
overview_stats() OverviewStats[source]

pycroft.lib.swdd

get_swdd_person_id(first_name: str, last_name: str, birthdate: date) int | None[source]

Builds a hmac hash from the given parameters and searches for a match in the Tenancy view

Parameters
  • first_name – The first name

  • last_name – The last name

  • birth_date – Date in ISO-8601

Returns

The person_id if found, else None

get_relevant_tenancies(person_id: int) list[Tenancy][source]
get_first_tenancy_with_room(tenancies: list[Tenancy]) Tenancy | None[source]

pycroft.lib.task

class TaskImpl[source]
name: str
abstract property type: TaskType
new_status: TaskStatus | None = None
errors: list[str] = []
execute(task: TTask) None[source]
class UserTaskImpl[source]
schedule(due: DateTimeTz, user: User, parameters: TParams, processor: User) UserTask[source]
class UserMoveOutTaskImpl[source]
name: str = 'Auszug'
type = 1
class UserMoveTaskImpl[source]
name: str = 'Umzug'
type = 3
class UserMoveInTaskImpl[source]
name: str = 'Einzug'
type = 2
get_task_implementation(task: Task) TaskImpl[source]
schedule_user_task(task_type: TaskType, due: DateTimeTz, user: User, parameters: TaskParams, processor: User | None) UserTask[source]
get_active_tasks_by_type(type: TaskType) Sequence[Type[Task]][source]
get_scheduled_tasks(session: Session) Sequence[Task][source]
cancel_task(task: Task, processor: User) None[source]
manually_execute_task(task: Task, processor: User) None[source]
reschedule_task(task: Task, due: datetime, processor: User) None[source]

pycroft.lib.traffic

This module contains functions concerning network traffic

class UserTrafficInfo(*args, **kwargs)[source]
id: int
name: str
traffic_for_days: int
get_users_with_highest_traffic(days: int, limit: int) list[UserTrafficInfo][source]
delete_old_traffic_data(session: Session) int[source]

pycroft.lib.user_deletion

This module contains methods concerning user archival and deletion.

class ArchivableMemberInfo(*args, **kwargs)[source]
User: User
mem_id: int
mem_end: datetime
get_archivable_members(session: Session) Sequence[ArchivableMemberInfo][source]

Return all the users that qualify for being archived right now.

Selected are those users - whose last membership in the member_group ended two weeks in the past, - excluding users who currently have the do-not-archive property.

get_invalidated_archive_memberships() list[Membership][source]

Get all memberships in to_be_archived of users who have an active do-not-archive property.

This can happen if archivability is detected, and later the user becomes a member again, or if for some reason the user shall not be archived.