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

1""" 

2General endpoints for Tator that are used throughout the application. 

3 

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

16 

17import base64 

18import json 

19 

20import tator 

21import requests 

22from flask import current_app, request, session, Response 

23 

24from . import tator_bp 

25from ..util.tator_localization_type import TatorLocalizationType 

26 

27 

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 

44 

45 

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 

60 

61 

62# clears stored tator token 

63@tator_bp.get('/logout') 

64def tator_logout(): 

65 session.pop('tator_token', None) 

66 return {}, 200 

67 

68 

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 

80 

81 

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 

93 

94 

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 

126 

127 

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 

135 

136 

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 

155 

156 

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 

174 

175 

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 

210 

211 

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