From e5b3e042514b20dbc52c589c078ade01c11c1b29 Mon Sep 17 00:00:00 2001 From: Hendrik Wolff Date: Tue, 13 Feb 2024 23:47:59 +0100 Subject: [PATCH 1/3] Add tenancies to room view --- web/blueprints/facilities/__init__.py | 27 ++++++++++++++++++++++++- web/blueprints/facilities/tables.py | 20 ++++++++++++++++++ web/templates/facilities/room_show.html | 9 +++++++++ 3 files changed, 55 insertions(+), 1 deletion(-) diff --git a/web/blueprints/facilities/__init__.py b/web/blueprints/facilities/__init__.py index ce751e6a0..516037f95 100644 --- a/web/blueprints/facilities/__init__.py +++ b/web/blueprints/facilities/__init__.py @@ -58,7 +58,7 @@ from web.blueprints.helpers.log import format_room_log_entry from web.blueprints.helpers.user import user_button from web.blueprints.navigation import BlueprintNavigation -from web.table.table import TableResponse, LinkColResponse, BtnColResponse +from web.table.table import TableResponse, LinkColResponse, BtnColResponse, date_format from .address import get_address_entity, address_entity_search_query from .tables import ( BuildingLevelRoomTable, @@ -70,9 +70,12 @@ BuildingLevelRoomRow, PatchPortRow, RoomOvercrowdedRow, + RoomTenanciesTable, + RoomTenanciesRow, ) from ..helpers.exception import abort_on_error, ErrorHandlerMap from ..helpers.log_tables import LogTableRow +from ...template_filters import date_filter bp = Blueprint('facilities', __name__) access = BlueprintAccess(bp, required_properties=['facilities_show']) @@ -519,6 +522,11 @@ def room_show(room_id: int) -> ResponseReturnValue: patch_port_table = PatchPortTable(data_url=url_for(".room_patchpanel_json", room_id=room.id), room_id=room_id) + room_tenancies_table = RoomTenanciesTable( + data_url=url_for(".room_tenancies_json", room_id=room.id), + table_args={"data-search": "false"}, + ) + return render_template( "facilities/room_show.html", page_title=f"Raum {room.short_name}", @@ -535,6 +543,7 @@ def room_show(room_id: int) -> ResponseReturnValue: ], room_log_table=room_log_table, patch_port_table=patch_port_table, + room_tenancies_table=room_tenancies_table, form=form, ) @@ -600,6 +609,22 @@ def room_patchpanel_json(room_id: int) -> ResponseReturnValue: ).model_dump() +@bp.route("/room//tenancies/json") +def room_tenancies_json(room_id: int) -> ResponseReturnValue: + room = get_room_or_404(room_id) + return TableResponse[RoomTenanciesRow]( + items=[ + RoomTenanciesRow( + inhabitant=user_button(tenancy.user), + begins_at=date_format(tenancy.mietbeginn, formatter=date_filter), + ends_at=date_format(tenancy.mietende, formatter=date_filter), + status=tenancy.status.name, + ) + for tenancy in room.tenancies + ] + ).model_dump() + + @bp.route('/json/levels') @access.require('facilities_show') def json_levels() -> ResponseReturnValue: diff --git a/web/blueprints/facilities/tables.py b/web/blueprints/facilities/tables.py index fc1421281..d011cc1c0 100644 --- a/web/blueprints/facilities/tables.py +++ b/web/blueprints/facilities/tables.py @@ -15,6 +15,7 @@ DateColumn, LinkColResponse, BtnColResponse, + DateColResponse, ) from web.blueprints.infrastructure.tables import no_inf_change @@ -104,3 +105,22 @@ class PatchPortRow(BaseModel): switch_port: LinkColResponse | None = None edit_link: BtnColResponse delete_link: BtnColResponse + + +class RoomTenanciesTable(BootstrapTable): + _render_toolbar = False + + inhabitants = BtnColumn("Bewohner") + begins_at = DateColumn("Von") + ends_at = DateColumn("Bis") + status = Column("Status") + + class Meta: + table_args = {"data-sort-name": "begins_at"} + + +class RoomTenanciesRow(BaseModel): + inhabitant: BtnColResponse + begins_at: DateColResponse + ends_at: DateColResponse + status: str diff --git a/web/templates/facilities/room_show.html b/web/templates/facilities/room_show.html index 0855484fe..4845ca24c 100644 --- a/web/templates/facilities/room_show.html +++ b/web/templates/facilities/room_show.html @@ -87,6 +87,15 @@

Bewohner history

+
+ + {% if room_tenancies_table %} + {{ room_tenancies_table.render("room_tenancies_table") }} + {% else %} + Dieser Raum hat keine Mietverhältnisse + {% endif %} +
+
{% if ports %} From 8b41969f2c5baf9dc85fedbdddb2ac01089ddbb9 Mon Sep 17 00:00:00 2001 From: Lukas Juhrich Date: Fri, 29 Mar 2024 19:54:24 +0100 Subject: [PATCH 2/3] Add simple table test --- tests/frontend/test_facilities.py | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/tests/frontend/test_facilities.py b/tests/frontend/test_facilities.py index 294f43c37..24d4c9b11 100644 --- a/tests/frontend/test_facilities.py +++ b/tests/frontend/test_facilities.py @@ -9,6 +9,7 @@ from pycroft.model.facilities import Building, Room, Site from pycroft.model.port import PatchPort from web.blueprints.facilities.address import ADDRESS_ENTITIES +from web.blueprints.facilities.tables import RoomTenanciesRow from tests import factories as f from tests.factories import RoomFactory from .assertions import TestClient @@ -136,6 +137,28 @@ def test_building_level_rooms( ) +class TestRoomTenancies: + @pytest.fixture(scope="class") + def user(self, class_session): + return f.UserFactory(swdd_person_id="1") + + @pytest.fixture(scope="class") + def room(self, class_session): + return f.RoomFactory(swdd_vo_suchname="1") + + def test_room_tenancies_json(self, room, user, session, client): + resp = client.assert_url_ok( + url_for( + "facilities.room_tenancies_json", + room_id=room.id, + ) + ) + assert (items := resp.json.get("items")) + assert len(items) == 1 + tenancy_row = RoomTenanciesRow.model_validate(items[0]) + assert tenancy_row.inhabitant.title == user.name + + class TestOvercrowdedRooms: @pytest.fixture(scope="class", autouse=True) def building(self, class_session) -> Building: From 1b70dc269dff475b313e6e58a87d4af53d49d573 Mon Sep 17 00:00:00 2001 From: Lukas Juhrich Date: Fri, 29 Mar 2024 19:55:32 +0100 Subject: [PATCH 3/3] Allow tenancies without a user (maybe the user is nto mapped) --- web/blueprints/facilities/tables.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web/blueprints/facilities/tables.py b/web/blueprints/facilities/tables.py index d011cc1c0..4c60f5722 100644 --- a/web/blueprints/facilities/tables.py +++ b/web/blueprints/facilities/tables.py @@ -120,7 +120,7 @@ class Meta: class RoomTenanciesRow(BaseModel): - inhabitant: BtnColResponse + inhabitant: BtnColResponse | None = None begins_at: DateColResponse ends_at: DateColResponse status: str