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

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 

19 

20from pyramid.httpexceptions import HTTPBadRequest, HTTPNotFound, HTTPPreconditionFailed 

21from pyramid.request import Request 

22from pyramid.response import Response 

23from pyramid.view import view_config 

24 

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 

31 

32 

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 

38 

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) 

47 

48 

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} 

54 

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__()) 

67 

68 

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 

74 

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)) 

98 

99 facility.update_from_json(params) 

100 

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. 

103 

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 } 

112 

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 } 

120 

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" 

126 

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)) 

133 

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) 

140 

141 try: 

142 request.repo.facility_repo.update(facility) 

143 except ValueError as e: 

144 raise HTTPPreconditionFailed(body=str(e)) 

145 

146 return Response(status_code=HTTPStatus.OK, json_body=facility.__json__())