Skip to content

Commit 22a4de3

Browse files
authored
Merge pull request #195 from stuartcampbell/move-locking-endpoints
Move locking endpoints to admin
2 parents b598e8d + f959457 commit 22a4de3

6 files changed

Lines changed: 340 additions & 246 deletions

File tree

src/nsls2api/api/v1/admin_api.py

Lines changed: 205 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
from typing import Annotated, Optional
22

33
import fastapi
4-
from fastapi import Depends, HTTPException
4+
from fastapi import Depends, HTTPException, Query
5+
from starlette.responses import Response
56

67
from nsls2api.api.models.facility_model import FacilityName
7-
from nsls2api.api.models.proposal_model import SingleProposal
8+
from nsls2api.api.models.proposal_model import (
9+
LockedProposalsList,
10+
ProposalChangeResultsList,
11+
ProposalsToChangeList,
12+
SingleProposal,
13+
)
14+
from nsls2api.api.v1.proposal_api import router
815
from nsls2api.infrastructure import config
916
from nsls2api.infrastructure.security import (
1017
generate_api_key,
@@ -16,7 +23,7 @@
1623
ApiUserRole,
1724
ApiUserType,
1825
)
19-
from nsls2api.services import proposal_service
26+
from nsls2api.services import beamline_service, facility_service, proposal_service
2027

2128
# router = fastapi.APIRouter()
2229
router = fastapi.APIRouter(
@@ -104,3 +111,198 @@ async def update_user_role(username: str, role: ApiUserRole) -> ApiUserResponseM
104111
)
105112

106113
return response
114+
115+
116+
@router.put(
117+
"/admin/proposals/cycle/lock/{cycle_name}/{facility}",
118+
response_model=ProposalChangeResultsList,
119+
)
120+
async def lock_cycle(cycle_name: str, facility: str):
121+
cycle = await facility_service.cycle_exists(
122+
cycle_name=cycle_name, facility=facility
123+
)
124+
if not cycle:
125+
raise HTTPException(
126+
status_code=fastapi.status.HTTP_404_NOT_FOUND,
127+
detail=f"Cycle {cycle_name} not found",
128+
)
129+
page, page_size = 1, 100
130+
count = page_size
131+
proposals_to_change = []
132+
while count == page_size:
133+
proposals_at_cycle = await proposal_service.fetch_proposals(
134+
cycle=[cycle_name], facility=[facility], page=page, page_size=page_size
135+
)
136+
proposals_to_change.extend(
137+
[proposal.proposal_id for proposal in proposals_at_cycle]
138+
)
139+
count = len(proposals_at_cycle)
140+
page += 1
141+
142+
proposal_list = ProposalsToChangeList(proposals_to_change=proposals_to_change)
143+
locked_info = await proposal_service.lock(proposal_list)
144+
return locked_info
145+
146+
147+
@router.put(
148+
"/admin/proposals/cycle/unlock/{cycle_name}/{facility}",
149+
response_model=ProposalChangeResultsList,
150+
)
151+
async def unlock_cycle(cycle_name: str, facility: str):
152+
cycle = await facility_service.cycle_exists(
153+
cycle_name=cycle_name, facility=facility
154+
)
155+
if not cycle:
156+
raise HTTPException(
157+
status_code=fastapi.status.HTTP_404_NOT_FOUND,
158+
detail=f"Cycle {cycle_name} not found",
159+
)
160+
page, page_size = 1, 100
161+
count = page_size
162+
proposals_to_change = []
163+
while count == page_size:
164+
proposals_at_cycle = await proposal_service.fetch_proposals(
165+
cycle=[cycle_name], facility=[facility], page=page, page_size=page_size
166+
)
167+
proposals_to_change.extend(
168+
[proposal.proposal_id for proposal in proposals_at_cycle]
169+
)
170+
count = len(proposals_at_cycle)
171+
page += 1
172+
173+
proposal_list = ProposalsToChangeList(proposals_to_change=proposals_to_change)
174+
unlocked_info = await proposal_service.unlock(proposal_list)
175+
return unlocked_info
176+
177+
178+
@router.put(
179+
"/admin/proposals/beamline/unlock/{beamline_name}",
180+
response_model=ProposalChangeResultsList,
181+
)
182+
async def unlock_beamline(beamline_name: str):
183+
beamline = await beamline_service.beamline_by_name(beamline_name)
184+
if beamline is None:
185+
raise HTTPException(
186+
status_code=fastapi.status.HTTP_404_NOT_FOUND,
187+
detail=f"Beamline {beamline_name} not found",
188+
)
189+
page, page_size = 1, 100
190+
count = page_size
191+
proposals_to_change = []
192+
while count == page_size:
193+
proposals_at_beamline = await proposal_service.fetch_proposals(
194+
beamline=[beamline_name], page=page, page_size=page_size
195+
)
196+
proposals_to_change.extend(
197+
[proposal.proposal_id for proposal in proposals_at_beamline]
198+
)
199+
count = len(proposals_at_beamline)
200+
page += 1
201+
202+
proposal_list = ProposalsToChangeList(proposals_to_change=proposals_to_change)
203+
unlocked_info = await proposal_service.unlock(proposal_list)
204+
return unlocked_info
205+
206+
207+
@router.put(
208+
"/admin/proposals/beamline/lock/{beamline_name}",
209+
response_model=ProposalChangeResultsList,
210+
)
211+
async def lock_beamline(beamline_name: str):
212+
beamline = await beamline_service.beamline_by_name(beamline_name)
213+
if beamline is None:
214+
raise HTTPException(
215+
status_code=fastapi.status.HTTP_404_NOT_FOUND,
216+
detail=f"Beamline {beamline_name} not found",
217+
)
218+
page, page_size = 1, 100
219+
count = page_size
220+
proposals_to_change = []
221+
while count == page_size:
222+
proposals_at_beamline = await proposal_service.fetch_proposals(
223+
beamline=[beamline_name], page=page, page_size=page_size
224+
)
225+
proposals_to_change.extend(
226+
[proposal.proposal_id for proposal in proposals_at_beamline]
227+
)
228+
count = len(proposals_at_beamline)
229+
page += 1
230+
231+
proposal_list = ProposalsToChangeList(proposals_to_change=proposals_to_change)
232+
locked_info = await proposal_service.lock(proposal_list)
233+
return locked_info
234+
235+
236+
@router.put(
237+
"/admin/proposals/lock",
238+
response_model=ProposalChangeResultsList,
239+
)
240+
async def lock(proposal_list: ProposalsToChangeList, response: Response):
241+
unknown_proposals = [
242+
proposal
243+
for proposal in proposal_list.proposals_to_change
244+
if not await proposal_service.exists(proposal)
245+
]
246+
if unknown_proposals:
247+
raise HTTPException(
248+
status_code=fastapi.status.HTTP_404_NOT_FOUND,
249+
detail=f"Proposals {unknown_proposals} not found. No action taken.",
250+
)
251+
locked_info = await proposal_service.lock(proposal_list)
252+
if locked_info.failed_proposals:
253+
response.status_code = fastapi.status.HTTP_422_UNPROCESSABLE_ENTITY
254+
return locked_info
255+
256+
257+
@router.get("/admin/proposals/locked", response_model=LockedProposalsList)
258+
async def gather_locked_proposals(
259+
facility: str,
260+
beamline: Annotated[list[str], Query()] = [],
261+
cycle: Annotated[list[str], Query()] = [],
262+
):
263+
for beamline_name in beamline:
264+
beamline_info = await beamline_service.beamline_by_name(beamline_name)
265+
if beamline_info is None:
266+
raise HTTPException(
267+
status_code=fastapi.status.HTTP_404_NOT_FOUND,
268+
detail=f"Beamline {beamline_name} not found",
269+
)
270+
for cycle_name in cycle:
271+
if not await facility_service.cycle_exists(
272+
cycle_name=cycle_name, facility=facility
273+
):
274+
raise HTTPException(
275+
status_code=fastapi.status.HTTP_404_NOT_FOUND,
276+
detail=f"Cycle {cycle_name} not found",
277+
)
278+
locked_proposals = await proposal_service.get_locked_proposals(
279+
cycles=cycle, beamlines=beamline
280+
)
281+
locked_proposals_list = locked_proposals.locked_proposals
282+
if locked_proposals_list is None:
283+
raise HTTPException(
284+
status_code=fastapi.status.HTTP_204_NO_CONTENT,
285+
detail="No locked proposals found",
286+
)
287+
return locked_proposals
288+
289+
290+
@router.put(
291+
"/admin/proposals/unlock",
292+
response_model=ProposalChangeResultsList,
293+
)
294+
async def unlock(proposal_list: ProposalsToChangeList, response: Response):
295+
unknown_proposals = [
296+
proposal
297+
for proposal in proposal_list.proposals_to_change
298+
if not await proposal_service.exists(proposal)
299+
]
300+
if unknown_proposals:
301+
raise HTTPException(
302+
status_code=fastapi.status.HTTP_404_NOT_FOUND,
303+
detail=f"Proposals {unknown_proposals} not found. No action taken.",
304+
)
305+
unlocked_info = await proposal_service.unlock(proposal_list)
306+
if unlocked_info.failed_proposals:
307+
response.status_code = fastapi.status.HTTP_422_UNPROCESSABLE_ENTITY
308+
return unlocked_info

0 commit comments

Comments
 (0)