Coverage for application/tator/routes.py: 25%
118 statements
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-23 02:22 +0000
« prev ^ index » next coverage.py v7.9.1, created at 2025-06-23 02:22 +0000
1"""
2General endpoints for Tator that are used throughout the application.
4/tator/login [POST]
5/tator/token [GET]
6/tator/logout [GET]
7/tator/projects [GET]
8/tator/sections/<project_id> [GET]
9/tator/deployments/<project_id>/<section_id> [GET]
10/tator/refresh-sections [GET]
11/tator/frame/<media_id>/<frame> [GET]
12/tator/localization-image/<localization_id> [GET]
13/tator/localization [PATCH]
14/tator/localization/good-image [PATCH]
15"""
17import base64
18import json
20import tator
21import requests
22from flask import current_app, request, session, Response
24from . import tator_bp
25from ..util.tator_localization_type import TatorLocalizationType
28# log in to tator (get token from tator)
29@tator_bp.post('/login')
30def tator_login():
31 res = requests.post(
32 url=f'{current_app.config.get("TATOR_URL")}/rest/Token',
33 headers={'Content-Type': 'application/json'},
34 data=json.dumps({
35 'username': request.values.get('username'),
36 'password': request.values.get('password'),
37 'refresh': True,
38 }),
39 )
40 if res.status_code == 201:
41 session['tator_token'] = res.json()['token']
42 return {'username': request.values.get('username')}, 200
43 return {}, res.status_code
46# check if stored tator token is valid
47@tator_bp.get('/token')
48def check_tator_token():
49 if 'tator_token' not in session.keys():
50 return {}, 400
51 try:
52 api = tator.get_api(
53 host=current_app.config.get('TATOR_URL'),
54 token=session['tator_token'],
55 )
56 print(f'Your Tator token: {session["tator_token"]}')
57 return {'username': api.whoami().username}, 200
58 except tator.openapi.tator_openapi.exceptions.ApiException:
59 return {}, 400
62# clears stored tator token
63@tator_bp.get('/logout')
64def tator_logout():
65 session.pop('tator_token', None)
66 return {}, 200
69# get a list of projects associated with user from tator
70@tator_bp.get('/projects')
71def tator_projects():
72 try:
73 project_list = tator.get_api(
74 host=current_app.config.get('TATOR_URL'),
75 token=session.get('tator_token'),
76 ).get_project_list()
77 return [{'id': project.id, 'name': project.name} for project in project_list], 200
78 except tator.openapi.tator_openapi.exceptions.ApiException:
79 return {}, 400
82# get a list of sections associated with a project from tator
83@tator_bp.get('/sections/<project_id>')
84def tator_sections(project_id):
85 try:
86 section_list = tator.get_api(
87 host=current_app.config.get('TATOR_URL'),
88 token=session.get('tator_token'),
89 ).get_section_list(project_id)
90 return [{'id': section.id, 'name': section.name} for section in section_list], 200
91 except tator.openapi.tator_openapi.exceptions.ApiException:
92 return {}, 400
95# get a list of deployments associated with a project & section from tator
96@tator_bp.get('/deployments/<project_id>/<section_id>')
97def load_media(project_id, section_id):
98 if f'{project_id}_{section_id}' in session.keys() and request.args.get('refresh') != 'true':
99 return sorted(session[f'{project_id}_{section_id}'].keys()), 200
100 else:
101 deployment_list = {}
102 # REST is much faster than Python API for large queries
103 res = requests.get(
104 url=f'{current_app.config.get("TATOR_URL")}/rest/Medias/{project_id}?section={section_id}',
105 headers={
106 'Content-Type': 'application/json',
107 'Authorization': f'Token {session.get("tator_token")}',
108 })
109 if res.status_code != 200:
110 return {}, res.status_code
111 for media in res.json():
112 media_name_parts = media['name'].split('_')
113 # stupid solution until we decide on an actual naming convention...never?
114 if 'dscm' in media_name_parts and media_name_parts.index('dscm') == 2: # format SLB_2024_dscm_01_C001.MP4
115 deployment_name = '_'.join(media_name_parts[0:4])
116 elif 'dscm' in media_name_parts and media_name_parts.index('dscm') == 1: # format HAW_dscm_01_c010_202304250123Z_0983m.mp4
117 deployment_name = '_'.join(media_name_parts[0:3])
118 else: # format DOEX0087_NIU-dscm-02_c009.mp4
119 deployment_name = media_name_parts[1]
120 if deployment_name not in deployment_list.keys():
121 deployment_list[deployment_name] = [media['id']]
122 else:
123 deployment_list[deployment_name].append(media['id'])
124 session[f'{project_id}_{section_id}'] = deployment_list
125 return sorted(deployment_list.keys()), 200
128# deletes stored tator sections
129@tator_bp.get('/refresh-sections')
130def refresh_tator_sections():
131 for key in list(session.keys()):
132 if key.split('_')[0] == '26': # id for NGS-ExTech Project
133 session.pop(key)
134 return {}, 200
137# view tator video frame (not cropped)
138@tator_bp.get('/frame/<media_id>/<frame>')
139def tator_frame(media_id, frame):
140 if 'tator_token' in session.keys():
141 token = session['tator_token']
142 else:
143 token = request.args.get('token')
144 url = f'{current_app.config.get("TATOR_URL")}/rest/GetFrame/{media_id}?frames={frame}'
145 if request.values.get('preview'):
146 url += '&quality=650'
147 res = requests.get(
148 url=url,
149 headers={'Authorization': f'Token {token}'}
150 )
151 if res.status_code == 200:
152 base64_image = base64.b64encode(res.content).decode('utf-8')
153 return Response(base64.b64decode(base64_image), content_type='image/png'), 200
154 return '', 500
157# view tator localization image (cropped)
158@tator_bp.get('/localization-image/<localization_id>')
159def tator_image(localization_id):
160 if not session.get('tator_token'):
161 if not request.values.get('token'):
162 return {}, 400
163 token = request.values.get('token')
164 else:
165 token = session["tator_token"]
166 res = requests.get(
167 url=f'{current_app.config.get("TATOR_URL")}/rest/LocalizationGraphic/{localization_id}',
168 headers={'Authorization': f'Token {token}'}
169 )
170 if res.status_code == 200:
171 base64_image = base64.b64encode(res.content).decode('utf-8')
172 return Response(base64.b64decode(base64_image), content_type='image/png'), 200
173 return '', 500
176# update tator localization
177@tator_bp.patch('/localization')
178def update_tator_localization():
179 localization_id_types = json.loads(request.values.get('localization_id_types'))
180 attributes = {
181 'Scientific Name': request.values.get('scientific_name'),
182 'Qualifier': request.values.get('qualifier'),
183 'Reason': request.values.get('reason'),
184 'Tentative ID': request.values.get('tentative_id'),
185 'IdentificationRemarks': request.values.get('identification_remarks'),
186 'Morphospecies': request.values.get('morphospecies'),
187 'Identified By': request.values.get('identified_by'),
188 'Notes': request.values.get('notes'),
189 'Attracted': request.values.get('attracted'),
190 }
191 try:
192 for localization in localization_id_types:
193 this_attributes = attributes.copy()
194 if localization['type'] == TatorLocalizationType.DOT.value:
195 this_attributes['Categorical Abundance'] = request.values.get('categorical_abundance') if request.values.get('categorical_abundance') else '--'
196 api = tator.get_api(
197 host=current_app.config.get('TATOR_URL'),
198 token=session.get('tator_token'),
199 )
200 api.update_localization_by_elemental_id(
201 version=localization['version'],
202 elemental_id=localization['elemental_id'],
203 localization_update=tator.models.LocalizationUpdate(
204 attributes=this_attributes,
205 )
206 )
207 except tator.openapi.tator_openapi.exceptions.ApiException:
208 return {}, 500
209 return {}, 200
212# update tator localization 'good image'
213@tator_bp.patch('/localization/good-image')
214def update_tator_localization_image():
215 localization_elemental_ids = request.values.getlist('localization_elemental_ids')
216 version = request.values.get('version')
217 try:
218 for elemental_id in localization_elemental_ids:
219 api = tator.get_api(
220 host=current_app.config.get('TATOR_URL'),
221 token=session.get('tator_token'),
222 )
223 api.update_localization_by_elemental_id(
224 version=version,
225 elemental_id=elemental_id,
226 localization_update=tator.models.LocalizationUpdate(
227 attributes={
228 'Good Image': True if request.values.get('good_image') == 'true' else False,
229 },
230 )
231 )
232 except tator.openapi.tator_openapi.exceptions.ApiException:
233 return {}, 500
234 return {}, 200