Skip to content

Commit 200f411

Browse files
committed
get user_allowance, get/create user_allowance for bitstream and user, fetch bitstream, fetch bundle, get user by email, get http status, logout
1 parent ed12a06 commit 200f411

File tree

1 file changed

+172
-5
lines changed

1 file changed

+172
-5
lines changed

dspace_rest_client/client.py

Lines changed: 172 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -109,15 +109,17 @@ def __init__(self, api_endpoint=API_ENDPOINT, username=USERNAME, password=PASSWO
109109
self.request_headers = {'Content-type': 'application/json', 'User-Agent': self.USER_AGENT}
110110
self.list_request_headers = {'Content-type': 'text/uri-list', 'User-Agent': self.USER_AGENT}
111111

112-
def authenticate(self, retry=False):
112+
def authenticate(self, user=None, password=None, retry=False):
113113
"""
114114
Authenticate with the DSpace REST API. As with other operations, perform XSRF refreshes when necessary.
115115
After POST, check /authn/status and log success if the authenticated json property is true
116116
@return: response object
117117
"""
118+
user = user or self.USERNAME
119+
password = password or self.PASSWORD
118120
# Set headers for requests made during authentication
119121
# Get and update CSRF token
120-
r = self.session.post(self.LOGIN_URL, data={'user': self.USERNAME, 'password': self.PASSWORD},
122+
r = self.session.post(self.LOGIN_URL, data={'user': user, 'password': password},
121123
headers=self.auth_request_headers)
122124
self.update_token(r)
123125

@@ -131,12 +133,12 @@ def authenticate(self, retry=False):
131133
return False
132134
else:
133135
logging.debug("Retrying request with updated CSRF token")
134-
return self.authenticate(retry=True)
136+
return self.authenticate(user=user, password=password, retry=True)
135137

136138
if r.status_code == 401:
137139
# 401 Unauthorized
138140
# If we get a 401, this means a general authentication failure
139-
logging.error(f'Authentication failure: invalid credentials for user {self.USERNAME}')
141+
logging.error(f'Authentication failure: invalid credentials for user {user}')
140142
return False
141143

142144
# Update headers with new bearer token if present
@@ -148,7 +150,7 @@ def authenticate(self, retry=False):
148150
if r.status_code == 200:
149151
r_json = parse_json(r)
150152
if 'authenticated' in r_json and r_json['authenticated'] is True:
151-
logging.info(f'Authenticated successfully as {self.USERNAME}')
153+
logging.info(f'Authenticated successfully as {user}')
152154
return r_json['authenticated']
153155

154156
# Default, return false
@@ -702,6 +704,7 @@ def create_bitstream(self, bundle=None, name=None, path=None, mime=None, metadat
702704
logging.error(f'Error creating bitstream: {r.status_code}: {r.text}')
703705
return None
704706

707+
705708
def download_bitstream(self, uuid=None):
706709
"""
707710
Download bitstream and return full response object including headers, and content
@@ -858,6 +861,24 @@ def get_item(self, uuid):
858861
logging.error(f'Invalid item UUID: {uuid}')
859862
return None
860863

864+
def get_items_by_handle(self, handle):
865+
if handle is None:
866+
return None
867+
params = {
868+
"handle": handle
869+
}
870+
url = f'{self.API_ENDPOINT}/core/items/search/byHandle'
871+
try:
872+
r = self.api_get(url, params, None)
873+
r_json = parse_json(r)
874+
if '_embedded' in r_json:
875+
if 'items' in r_json['_embedded']:
876+
return r_json['_embedded']['items']
877+
return None
878+
except ValueError:
879+
logging.error(f'Invalid item handle: {handle}')
880+
return None
881+
861882
def get_items(self):
862883
"""
863884
Get all archived items for a logged-in administrator. Admin only! Usually you will want to
@@ -1128,3 +1149,149 @@ def update_resource_policy_group(self, policy_id, group_uuid):
11281149
body = f'{self.API_ENDPOINT}/eperson/groups/{group_uuid}'
11291150
r = self.api_put_uri(url, None, body, False)
11301151
return r
1152+
1153+
def get_clarinlruallowances(self):
1154+
"""
1155+
Fetch all clarinlruallowances.
1156+
"""
1157+
url = f'{self.API_ENDPOINT}/core/clarinlruallowances'
1158+
try:
1159+
response = self.api_get(url)
1160+
data = parse_json(response)
1161+
allowances = data.get('_embedded', {}).get('clarinlruallowances')
1162+
if allowances:
1163+
logging.info(f"Fetched {len(allowances)} CLARIN LRU allowances.")
1164+
return allowances
1165+
logging.warning("No CLARIN LRU allowances found.")
1166+
except Exception as e:
1167+
logging.error(f"Error fetching CLARIN LRU allowances [{url}]: {e}")
1168+
return None
1169+
1170+
def get_clarinlruallowances_by_bitstreama_and_user(self, bitstream_uuid, user_uuid):
1171+
"""
1172+
Fetch user allowances for a specific bitstream and user.
1173+
"""
1174+
url = f'{self.API_ENDPOINT}/core/clarinlruallowance/search/byBitstreamAndUser'
1175+
params = {'bitstreamUUID': bitstream_uuid, 'userUUID': user_uuid}
1176+
try:
1177+
response = self.api_get(url, params=params)
1178+
data = parse_json(response)
1179+
allowances = data.get('_embedded', {}).get('clarinlruallowances')
1180+
if allowances:
1181+
logging.info(f"Found {len(allowances)} user allowance(s).")
1182+
return allowances
1183+
logging.warning(f"No user allowances found for user: {user_uuid} and bitstream: {bitstream_uuid}")
1184+
except Exception as e:
1185+
logging.error(f"Error fetching user allowances: {e}")
1186+
return None
1187+
1188+
1189+
def create_clarinlruallowances(self, bitstream_uuid):
1190+
"""
1191+
Create clarinlruallowances for a bitstream for logged user
1192+
by managing user metadata of bitstream.
1193+
"""
1194+
url = f'{self.API_ENDPOINT}/core/clarinusermetadata/manage'
1195+
params = {'bitstreamUUID': bitstream_uuid}
1196+
metadata_payload = [
1197+
{"metadataKey": "NAME", "metadataValue": "Test"}
1198+
]
1199+
try:
1200+
response = self.api_post(url, json=metadata_payload, params=params)
1201+
if response.status_code == 200:
1202+
logging.info(f"User metadata access managed for bitstream: {bitstream_uuid}")
1203+
return True
1204+
logging.warning(f"Failed to manage user metadata: {response.status_code}")
1205+
except Exception as e:
1206+
logging.error(f"Error managing user metadata: {e}")
1207+
return False
1208+
1209+
1210+
def logout(self):
1211+
"""
1212+
Log out from the DSpace session.
1213+
"""
1214+
try:
1215+
response = self.session.post(f'{self.API_ENDPOINT}/authn/logout', headers=self.request_headers)
1216+
if response.status_code == 204:
1217+
self.session.cookies.clear()
1218+
self.session.headers.pop('Authorization', None)
1219+
logging.info("Logout successful.")
1220+
return True
1221+
else:
1222+
logging.error(f"Logout failed: {response.status_code} - {response.text}")
1223+
except Exception as e:
1224+
logging.error(f"Logout error: {e}")
1225+
return False
1226+
1227+
def get_http_status(self, url):
1228+
"""
1229+
Check the HTTP status code of a URL.
1230+
"""
1231+
if not url:
1232+
logging.warning("Provided URL is not defined.")
1233+
return None
1234+
try:
1235+
response = self.api_get(url)
1236+
logging.info(f"Checked URL status: {url} -> {response.status_code}")
1237+
return response.status_code
1238+
except Exception as e:
1239+
logging.error(f"Error getting URL status for {url}: {e}")
1240+
return None
1241+
1242+
1243+
def fetch_bundle(self, bundle_reference):
1244+
"""
1245+
Fetch a bundle either by UUID or URL.
1246+
"""
1247+
if not bundle_reference:
1248+
logging.warning("No bundle reference provided.")
1249+
return None
1250+
1251+
url = bundle_reference if "bundle" in bundle_reference else\
1252+
f'{self.API_ENDPOINT}/core/{bundle_reference}/bundle'
1253+
try:
1254+
response = self.api_get(url)
1255+
data = parse_json(response)
1256+
bundle = data.get('_embedded', {}).get('bundles', [{}])[0]
1257+
logging.info(f"Bundle retrieved: {bundle.get('uuid', 'unknown')}")
1258+
return bundle
1259+
except Exception as e:
1260+
logging.error(f"Error fetching bundle: {e}")
1261+
return None
1262+
1263+
def fetch_bitstreams(self, bitstream_reference):
1264+
"""
1265+
Fetch bitstreams either by UUID or direct URL.
1266+
"""
1267+
if not bitstream_reference:
1268+
logging.warning("No bitstream reference provided.")
1269+
return None
1270+
1271+
url = bitstream_reference if "bitstream" in bitstream_reference else \
1272+
f'{self.API_ENDPOINT}/core/{bitstream_reference}/bitstream'
1273+
try:
1274+
response = self.api_get(url)
1275+
data = parse_json(response)
1276+
bitstreams = data.get('_embedded', {}).get('bitstreams', [])
1277+
logging.info(f"Fetched {len(bitstreams)} bitstream(s).")
1278+
return bitstreams
1279+
except Exception as e:
1280+
logging.error(f"Error fetching bitstreams: {e}")
1281+
return None
1282+
1283+
1284+
def get_user_by_email(self, email):
1285+
"""
1286+
Retrieve user details using their email address.
1287+
"""
1288+
url = f'{self.API_ENDPOINT}/eperson/epersons/search/byEmail'
1289+
params = {'email': email}
1290+
try:
1291+
response = self.api_get(url, params=params)
1292+
user_data = parse_json(response)
1293+
logging.info(f"User fetched by email: {email}")
1294+
return User(user_data)
1295+
except Exception as e:
1296+
logging.error(f"Error retrieving user by email {email}: {e}")
1297+
return None

0 commit comments

Comments
 (0)