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

delete_membership(session: Session, membership_id: int, processor: User) None[source]
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

select_user_and_last_mem() Select[source]

Select users with their last membership of a user in the member group.

Returns

a select statement with columns user_id, mem_id, mem_end.

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
select_archivable_members(current_year: int, years_following_eom: int) tuple[Select, CTE][source]

Get all members whose year(end of last membership) + 1 + years_following_eom <= current year.

legal grounds:

The following data can be collected and processed until the end of the next calendar year after membership ends: […]

—Privacy policy §2

Returns

a tuple of statement and the last_mem CTE which can be reused for late injection of an order_by.

get_archivable_members(session: Session, current_year: int | None = None, years_following_eom: int | None = None) Sequence[ArchivableMemberInfo][source]

Get all members whose year(end of last membership) + 1 + years_following_eom <= current year.

legal grounds:

The following data can be collected and processed until the end of the next calendar year after membership ends: […]

—Privacy policy §2

Returns

a tuple of statement and the last_mem CTE which can be reused for late injection of an order_by.

scrubbable_mails_stmt(year: int) Select[source]

Users whose mails can be scrubbed

Definition:

Other e-mail addresses you provide, which are used for contacting you.

—Privacy policy §2.6

Returns

a tuple of statement and the last_mem CTE which can be reused for late injection of an order_by.

scrubbable_mails(session: Session) ScalarResult[User][source]
scrubbable_mails_count(session: Session, year: int) int | None[source]
scrub_mail(session: Session, user: User, author: User) None[source]
scrub_all_mails(session: Session, author: User, user_filter: Callable[[Select], Select] | None = None) ScalarResult[int][source]
scrub_all_mails_stmt(year: int, author_id: int, user_filter: Callable[[Select], Select] | None = None) Select[source]
scrubbable_hosts_stmt(year: int) Select[source]

All the hosts we can delete.

Deleting them will delete interfaces and assigned IPs by cascade.

Definition:

Your MAC and IP addresses, which are required to access the student network.

—Privacy policy §2.8

scrubbable_dates_of_birth_stmt(year: int) Select[source]

All the users whose date of birth we can delete.

Definition:

Your date of birth, which is required based on TKG §172.

—Privacy policy §2.9

scrubbable_swdd_person_ids(year: int) Select[source]

All the users whose swdd_person_id (“Debitorennummer”) we can delete

If available, your “Debitorennummer” of the Studentenwerk Dresden to get information about the rental object (room) and the rental period

—Privacy policy §2.10

scrubbable_room_history_entries(year: int) Select[source]

All the room history entries we can delete

Past residences in dormitories we are operating in to correctly book membership fees.

– Privacy policy §2.11

scrubbable_name(year: int) Select[source]

All the users whose name can be deleted

The name of the user.

—Privacy policy §2.1

scrubbable_address(year: int) Select[source]

All the users whose address_id can be deleted

The former address of the user.

—Privacy policy §2.1