Coverage for middle_layer/solicit/application_layer/rest_api/views/facility.py: 75.86%
58 statements
« prev ^ index » next coverage.py v7.10.5, created at 2026-03-09 06:13 +0000
« prev ^ index » next coverage.py v7.10.5, created at 2026-03-09 06:13 +0000
1# Copyright 2024 Associated Universities, Inc.
2#
3# This file is part of Telescope Time Allocation Tools (TTAT).
4#
5# TTAT is free software: you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation, either version 3 of the License, or
8# any later version.
9#
10# TTAT is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with TTAT. If not, see <https://www.gnu.org/licenses/>.
17#
18from http import HTTPStatus
20from pyramid.httpexceptions import HTTPBadRequest, HTTPNotFound, HTTPPreconditionFailed
21from pyramid.request import Request
22from pyramid.response import Response
23from pyramid.view import view_config
25from common.application_layer.rest_api import make_expected_params_message
26from solicit.domain_layer.entities.array_configuration import ArrayConfiguration
27from solicit.domain_layer.entities.backend import Backend
28from solicit.domain_layer.entities.capability import Facility
29from solicit.domain_layer.entities.frontend import Frontend
30from solicit.domain_layer.entities.station import Station
33@view_config(route_name="facilities_list", renderer="json", permission="facilities_list")
34def facilities_list(request: Request) -> Response:
35 """
36 Get a list of all Facility objects
37 URL: facilities
39 :param request: GET request
40 :return: Response with JSON-formatted array of Facility objects
41 """
42 facilities = request.repo.facility_repo.list_all()
43 response = []
44 for facility in facilities:
45 response.append(facility.__json__())
46 return Response(status_code=HTTPStatus.OK, json_body=response)
49@view_config(route_name="facility_by_id", renderer="json", permission="facility_by_id")
50def facility_by_id(request: Request) -> Response:
51 """
52 Get a Facility by id
53 URL: facilities/{id}
55 :param request: GET request
56 :return: Response with JSON-formatted Facility
57 or 400 response (HTTPBadRequest) if the id was not an int
58 or 404 response (HTTPNotFound) if the Facility was not found
59 """
60 try:
61 facility = request.lookup(request.matchdict["id"], Facility)
62 except NameError as e:
63 raise HTTPBadRequest(body=str(e))
64 except ValueError as e:
65 raise HTTPNotFound(body=str(e))
66 return Response(status_code=HTTPStatus.OK, json_body=facility.__json__())
69@view_config(route_name="facility_update", renderer="json", permission="facility_update")
70def facility_update(request: Request) -> Response:
71 """
72 Update a Facility: name and isActive can be updated
73 URL: facilities
75 :param request: PUT request with JSON object like:
76 {
77 "facilityId": int,
78 "description": str,
79 "isActive": bool
80 }
81 :return: Response with JSON-formatted new or updated Facility
82 or 400 response (HTTPBadRequest) if expected parameters not given or id is not an int
83 or 404 response (HTTPNotFound) if Facility could not be found given the specified facilityId
84 or 412 response (HTTPPreconditionFailed) if Facility with given name already exists
85 """
86 expected_params = ["facilityId", "description", "isActive"]
87 params = request.json_body
88 if not all([expected in params for expected in expected_params]):
89 # JSON params do not contain all expected params
90 raise HTTPBadRequest(body=make_expected_params_message(expected_params, params.keys()))
91 else:
92 try:
93 facility = request.lookup(params["facilityId"], Facility)
94 except NameError as e:
95 raise HTTPBadRequest(body=str(e))
96 except ValueError as e:
97 raise HTTPNotFound(body=str(e))
99 facility.update_from_json(params)
101 # the following block handles the fact that we have four things that are basically just names,
102 # sitting in four different arrays hanging off of the Facility object.
104 # first we need some structures:
105 # Maps the JS field name to the Python field name (singular)
106 pyattrs = {
107 "frontends": "frontend",
108 "backends": "backend",
109 "stations": "station",
110 "arrayConfigurations": "array_configuration",
111 }
113 # Maps the JS field name to the model class
114 classes = {
115 "frontends": Frontend,
116 "backends": Backend,
117 "stations": Station,
118 "arrayConfigurations": ArrayConfiguration,
119 }
121 # now we're going to manage each attribute, coming from the JS name to the other two names above
122 for js_attribute in ["frontends", "backends", "stations", "arrayConfigurations"]:
123 python_name = pyattrs[js_attribute] + "_name" # e.g. array_configuration_name
124 js_name = js_attribute[:-1] + "Name" # e.g. "arrayConfigurationName"
125 facility_field = pyattrs[js_attribute] + "s" # e.g. "array_configurations"
127 # iterating over each entity in the submission, we're going to see if we have it already, and if we do not,
128 # we are going to add it
129 for uploaded_entity in params.get(js_attribute, []):
130 if uploaded_entity[js_name] not in (getattr(f, python_name) for f in getattr(facility, facility_field)):
131 cargs = {python_name: uploaded_entity[js_name]}
132 getattr(facility, facility_field).append(classes[js_attribute](**cargs))
134 # now for each entity we have on the facility already, if we do _not_ have that entity in the submission,
135 # we will remove it.
136 # it's important to iterate a copy of your collection if you are removing things from that collection
137 for existing_entity in getattr(facility, facility_field).copy():
138 if getattr(existing_entity, python_name) not in (f[js_name] for f in params.get(js_attribute, [])):
139 getattr(facility, facility_field).remove(existing_entity)
141 try:
142 request.repo.facility_repo.update(facility)
143 except ValueError as e:
144 raise HTTPPreconditionFailed(body=str(e))
146 return Response(status_code=HTTPStatus.OK, json_body=facility.__json__())