Skip to content

Commit 560654b

Browse files
committed
Implement fylr compatibility
1 parent 18e0d56 commit 560654b

4 files changed

Lines changed: 107 additions & 17 deletions

File tree

src/main/java/edu/harvard/mcz/imagecapture/ImageCaptureProperties.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -259,9 +259,12 @@ public class ImageCaptureProperties extends AbstractTableModel {
259259
public static String KEY_NAHIMA_URL = "nahima.url";
260260
public static String KEY_NAHIMA_PASSWORD = "nahima.password";
261261
public static String KEY_NAHIMA_USER = "nahima.user";
262+
public static String KEY_NAHIMA_CLIENT_ID = "nahima.client-id";
263+
public static String KEY_NAHIMA_CLIENT_SECRET = "nahima.client-secret";
262264
public static String KEY_NAHIMA_INTERACTIVE = "nahima.interactive";
263265
public static String KEY_NAHIMA_THREAD_POOL_SIZE = "nahima.threadpoolsize";
264266
private final String propertiesFilename = "imagecapture.properties";
267+
265268
/**
266269
* Private properties
267270
*/

src/main/java/edu/harvard/mcz/imagecapture/data/NahimaManager.java

Lines changed: 94 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,13 @@ public class NahimaManager extends AbstractRestClient {
5555
private static final Logger log =
5656
LoggerFactory.getLogger(NahimaManager.class);
5757
private final String url;
58+
private final String baseUrl;
5859
private final String username;
5960
private final String password;
61+
private final String clientId;
62+
private final String clientSecret;
63+
private final boolean useOAuth;
64+
private final String tokenParamName;
6065
private final boolean interactive;
6166
private final ConcurrentHashMap<String, Map<String, JSONObject>>
6267
resolveCache = new ConcurrentHashMap<>();
@@ -65,27 +70,49 @@ public class NahimaManager extends AbstractRestClient {
6570
public NahimaManager(String url, String username, String password,
6671
boolean interactive)
6772
throws IOException, InterruptedException {
68-
this(url, username, password, interactive, true);
73+
this(url, username, password, null, null, interactive, true);
6974
}
7075

7176
public NahimaManager(String url, String username, String password,
7277
boolean interactive, boolean requiresLogin)
7378
throws IOException, InterruptedException, RuntimeException {
79+
this(url, username, password, null, null, interactive, requiresLogin);
80+
}
81+
82+
public NahimaManager(String url, String username, String password,
83+
String clientId, String clientSecret,
84+
boolean interactive)
85+
throws IOException, InterruptedException, RuntimeException {
86+
this(url, username, password, clientId, clientSecret, interactive, true);
87+
}
88+
89+
public NahimaManager(String url, String username, String password,
90+
String clientId, String clientSecret,
91+
boolean interactive, boolean requiresLogin)
92+
throws IOException, InterruptedException, RuntimeException {
7493
// normalize URL
7594
if (!url.endsWith("/")) {
7695
url = url + "/";
7796
}
78-
if (!url.endsWith("api/v1/")) {
79-
url = url + "api/v1/";
80-
}
97+
98+
this.baseUrl = url;
99+
this.clientId = clientId;
100+
this.clientSecret = clientSecret;
101+
this.useOAuth = !isNullOrBlank(clientId) && !isNullOrBlank(clientSecret);
102+
this.tokenParamName = useOAuth ? "access_token" : "token";
103+
81104
// store properties
82-
this.url = url;
105+
this.url = this.baseUrl + (useOAuth ? "api/" : "api/v1/");
83106
this.username = username;
84107
this.password = password;
85108
this.interactive = interactive;
86109

87-
this.startSessionAndRetrieveToken();
88-
this.login();
110+
if (useOAuth) {
111+
this.retrieveOAuthToken();
112+
} else {
113+
this.startSessionAndRetrieveToken();
114+
this.login();
115+
}
89116
}
90117

91118
/**
@@ -146,6 +173,9 @@ protected void startSessionAndRetrieveToken() throws RuntimeException {
146173
*/
147174
protected void login()
148175
throws IOException, InterruptedException, RuntimeException {
176+
if (useOAuth) {
177+
return;
178+
}
149179
String queryUrl =
150180
this.url + "session/authenticate?method=easydb&token=" + this.token;
151181
HashMap<String, String> params = new HashMap<>();
@@ -167,6 +197,56 @@ protected void login()
167197
}
168198
}
169199

200+
protected void retrieveOAuthToken()
201+
throws IOException, InterruptedException, RuntimeException {
202+
String queryUrl = this.baseUrl + "api/oauth2/token";
203+
HashMap<String, String> params = new HashMap<>();
204+
params.put("grant_type", "password");
205+
params.put("username", this.username);
206+
params.put("password", this.password);
207+
params.put("client_id", this.clientId);
208+
params.put("client_secret", this.clientSecret);
209+
210+
String response = this.postRequest(queryUrl, params);
211+
JSONObject responseObject = new JSONObject(response);
212+
if (responseObject.has("error")) {
213+
throw new RuntimeException(
214+
"Failed to acquire OAuth2 token. Error: " +
215+
responseObject.optString("error") +
216+
(responseObject.has("error_description")
217+
? ": " + responseObject.optString("error_description")
218+
: ""));
219+
}
220+
if (!responseObject.has("access_token")) {
221+
throw new RuntimeException(
222+
"Failed to acquire OAuth2 token: missing access_token in response.");
223+
}
224+
this.token = responseObject.getString("access_token");
225+
}
226+
227+
private boolean isNullOrBlank(String value) {
228+
return value == null || value.trim().isEmpty();
229+
}
230+
231+
private String buildAuthenticatedUrl(String endpoint) {
232+
return buildAuthenticatedUrl(endpoint, null);
233+
}
234+
235+
private String buildAuthenticatedUrl(String endpoint, String queryParams) {
236+
StringBuilder urlBuilder = new StringBuilder();
237+
urlBuilder.append(this.url);
238+
urlBuilder.append(endpoint);
239+
urlBuilder.append("?");
240+
urlBuilder.append(tokenParamName);
241+
urlBuilder.append("=");
242+
urlBuilder.append(this.token);
243+
if (queryParams != null && !queryParams.trim().isEmpty()) {
244+
urlBuilder.append("&");
245+
urlBuilder.append(queryParams);
246+
}
247+
return urlBuilder.toString();
248+
}
249+
170250
/**
171251
* This function loops the images in a Specimen and uploads them to Nahima
172252
*
@@ -179,7 +259,7 @@ protected void login()
179259
// docs:
180260
// https://docs.easydb.de/en/technical/api/eas/
181261
// https://docs.easydb.de/en/sysadmin/eas/api/put/
182-
String baseQueryUrl = this.url + "eas/put?token=" + this.token;
262+
String baseQueryUrl = buildAuthenticatedUrl("eas/put");
183263
ArrayList<JSONObject> results = new ArrayList<>();
184264
HashMap<String, JSONObject> existingFilenames = new HashMap<>();
185265
if (existingExport != null &&
@@ -274,7 +354,7 @@ public JSONObject createObjectInNahima(JSONObject object, String objType)
274354
throws IOException, InterruptedException {
275355
// docs:
276356
// https://docs.easydb.de/en/technical/api/db/
277-
String queryURL = this.url + "db/" + objType + "?token=" + token;
357+
String queryURL = buildAuthenticatedUrl("db/" + objType);
278358
// EasyDB seems to have mixed up PUT & POST, but well, we don't care
279359
String returnValue = this.putRequest(
280360
queryURL, (new JSONArray()).put(object).toString(), new HashMap<>() {
@@ -308,7 +388,7 @@ public JSONObject createObjectInNahima(JSONObject object, String objType)
308388
}
309389

310390
public JSONObject findObjectByUuid(String uuid) throws IOException {
311-
String queryURL = this.url + "objects/uuid/" + uuid + "?token=" + token;
391+
String queryURL = buildAuthenticatedUrl("objects/uuid/" + uuid);
312392
String returnValue = this.getRequest(queryURL, new HashMap<>() {
313393
{
314394
put("Content-Type", "application/json");
@@ -343,8 +423,7 @@ public JSONObject findObjectByGlobalObjectId(String globalObjectId)
343423
return null;
344424
}
345425

346-
String queryURL = this.url + "search"
347-
+ "?token=" + token;
426+
String queryURL = buildAuthenticatedUrl("search");
348427
JSONObject query = new JSONObject() {
349428
{
350429
put("best_mask_filter", true);
@@ -449,8 +528,7 @@ public JSONObject searchByString(String searchString,
449528
}
450529

451530
// load fresh
452-
String queryURL = this.url + "search"
453-
+ "?token=" + token;
531+
String queryURL = buildAuthenticatedUrl("search");
454532
JSONArray search = new JSONArray();
455533

456534
String[] splitName = searchString.split(" ");
@@ -1303,7 +1381,7 @@ public JSONObject resolveCountry(String countryName, String isoCountryCode)
13031381
query.put("objecttypes", new JSONArray().put("gazetteer"));
13041382

13051383
// Execute the search
1306-
String queryURL = this.url + "search?token=" + token;
1384+
String queryURL = buildAuthenticatedUrl("search");
13071385
JSONObject result = this.postRequest(queryURL, query);
13081386

13091387
if (result.has("code") && result.getString("code").startsWith("error")) {
@@ -2048,7 +2126,7 @@ public JSONObject findTagWithName(String name) throws IOException {
20482126
return tagFromCache;
20492127
}
20502128

2051-
String queryUrl = this.url + "tags?token=" + this.token;
2129+
String queryUrl = buildAuthenticatedUrl("tags");
20522130

20532131
String response = this.getRequest(queryUrl);
20542132
if (!response.startsWith("[")) {

src/main/java/edu/harvard/mcz/imagecapture/jobs/NahimaExportJob.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,8 @@ public void start() throws Exception {
134134
properties.getProperty(ImageCaptureProperties.KEY_NAHIMA_URL),
135135
properties.getProperty(ImageCaptureProperties.KEY_NAHIMA_USER),
136136
properties.getProperty(ImageCaptureProperties.KEY_NAHIMA_PASSWORD),
137+
properties.getProperty(ImageCaptureProperties.KEY_NAHIMA_CLIENT_ID),
138+
properties.getProperty(ImageCaptureProperties.KEY_NAHIMA_CLIENT_SECRET),
137139
CastUtility.castToBoolean(properties.getOrDefault(
138140
ImageCaptureProperties.KEY_NAHIMA_INTERACTIVE, true)));
139141
return manager;

src/main/java/edu/harvard/mcz/imagecapture/ui/frame/SpecimenDetailsViewPane.java

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1822,7 +1822,14 @@ public void actionPerformed(java.awt.event.ActionEvent e) {
18221822
urlString = properties.getProperty(ImageCaptureProperties.KEY_NAHIMA_URL, "https://nahima.ethz.ch");
18231823

18241824
// need to first convert he global object id to the uuid for the link
1825-
NahimaManager nahimaManager = new NahimaManager(properties.getProperty(ImageCaptureProperties.KEY_NAHIMA_URL), properties.getProperty(ImageCaptureProperties.KEY_NAHIMA_USER), properties.getProperty(ImageCaptureProperties.KEY_NAHIMA_PASSWORD), false, false);
1825+
NahimaManager nahimaManager = new NahimaManager(
1826+
properties.getProperty(ImageCaptureProperties.KEY_NAHIMA_URL),
1827+
properties.getProperty(ImageCaptureProperties.KEY_NAHIMA_USER),
1828+
properties.getProperty(ImageCaptureProperties.KEY_NAHIMA_PASSWORD),
1829+
properties.getProperty(ImageCaptureProperties.KEY_NAHIMA_CLIENT_ID),
1830+
properties.getProperty(ImageCaptureProperties.KEY_NAHIMA_CLIENT_SECRET),
1831+
false,
1832+
false);
18261833

18271834
JSONObject nahimaEntry = nahimaManager.findObjectByGlobalObjectId(specimen.getNahimaId());
18281835

0 commit comments

Comments
 (0)