|
4 | 4 | import logging
|
5 | 5 | import re
|
6 | 6 | from datetime import date, timedelta
|
7 |
| -from typing import Dict, List |
8 | 7 |
|
9 | 8 | import requests
|
10 | 9 |
|
11 |
| -from fossology.exceptions import ( |
12 |
| - AuthenticationError, |
13 |
| - AuthorizationError, |
14 |
| - FossologyApiError, |
15 |
| - FossologyUnsupported, |
16 |
| -) |
| 10 | +from fossology.exceptions import AuthenticationError, FossologyApiError |
17 | 11 | from fossology.folders import Folders
|
18 | 12 | from fossology.groups import Groups
|
19 | 13 | from fossology.jobs import Jobs
|
20 | 14 | from fossology.license import LicenseEndpoint
|
21 |
| -from fossology.obj import ( |
22 |
| - Agents, |
23 |
| - ApiInfo, |
24 |
| - File, |
25 |
| - HealthInfo, |
26 |
| - SearchTypes, |
27 |
| - TokenScope, |
28 |
| - Upload, |
29 |
| - User, |
30 |
| - get_options, |
31 |
| -) |
| 15 | +from fossology.obj import Agents, ApiInfo, HealthInfo, TokenScope, User, versiontuple |
32 | 16 | from fossology.report import Report
|
| 17 | +from fossology.search import Search |
33 | 18 | from fossology.uploads import Uploads
|
| 19 | +from fossology.users import Users |
34 | 20 |
|
35 | 21 | logger = logging.getLogger(__name__)
|
36 | 22 | logger.setLevel(logging.DEBUG)
|
37 | 23 |
|
38 | 24 |
|
39 |
| -def versiontuple(v): |
40 |
| - return tuple(map(int, (v.split(".")))) |
41 |
| - |
42 |
| - |
43 |
| -def search_headers( |
44 |
| - searchType: SearchTypes = SearchTypes.ALLFILES, |
45 |
| - upload: Upload = None, |
46 |
| - filename: str = None, |
47 |
| - tag: str = None, |
48 |
| - filesizemin: int = None, |
49 |
| - filesizemax: int = None, |
50 |
| - license: str = None, |
51 |
| - copyright: str = None, |
52 |
| - group: str = None, |
53 |
| -) -> Dict: |
54 |
| - headers = {"searchType": searchType.value} |
55 |
| - if upload: |
56 |
| - headers["uploadId"] = str(upload.id) |
57 |
| - if filename: |
58 |
| - headers["filename"] = filename |
59 |
| - if tag: |
60 |
| - headers["tag"] = tag |
61 |
| - if filesizemin: |
62 |
| - headers["filesizemin"] = filesizemin |
63 |
| - if filesizemax: |
64 |
| - headers["filesizemax"] = filesizemax |
65 |
| - if license: |
66 |
| - headers["license"] = license |
67 |
| - if copyright: |
68 |
| - headers["copyright"] = copyright |
69 |
| - if group: |
70 |
| - headers["groupName"] = group |
71 |
| - return headers |
72 |
| - |
73 |
| - |
74 | 25 | def fossology_token(
|
75 | 26 | url, username, password, token_name, token_scope=TokenScope.READ, token_expire=None
|
76 | 27 | ):
|
@@ -128,7 +79,7 @@ def fossology_token(
|
128 | 79 | exit(f"Server {url} does not seem to be running or is unreachable: {error}")
|
129 | 80 |
|
130 | 81 |
|
131 |
| -class Fossology(Folders, Groups, LicenseEndpoint, Uploads, Jobs, Report): |
| 82 | +class Fossology(Folders, Groups, LicenseEndpoint, Uploads, Jobs, Report, Users, Search): |
132 | 83 |
|
133 | 84 | """Main Fossology API class
|
134 | 85 |
|
@@ -257,182 +208,3 @@ def get_health(self) -> ApiInfo:
|
257 | 208 | else:
|
258 | 209 | description = "Error while getting health info"
|
259 | 210 | raise FossologyApiError(description, response)
|
260 |
| - |
261 |
| - def detail_user(self, user_id): |
262 |
| - """Get details of Fossology user. |
263 |
| -
|
264 |
| - API Endpoint: GET /users/{id} |
265 |
| -
|
266 |
| - :param id: the ID of the user |
267 |
| - :type id: int |
268 |
| - :return: the requested user's details |
269 |
| - :rtype: User |
270 |
| - :raises FossologyApiError: if the REST call failed |
271 |
| - """ |
272 |
| - response = self.session.get(f"{self.api}/users/{user_id}") |
273 |
| - if response.status_code == 200: |
274 |
| - user_agents = None |
275 |
| - user_details = response.json() |
276 |
| - if user_details.get("agents"): |
277 |
| - user_agents = Agents.from_json(user_details["agents"]) |
278 |
| - user = User.from_json(user_details) |
279 |
| - user.agents = user_agents |
280 |
| - return user |
281 |
| - else: |
282 |
| - description = f"Error while getting details for user {user_id}" |
283 |
| - raise FossologyApiError(description, response) |
284 |
| - |
285 |
| - def list_users(self): |
286 |
| - """List all users from the Fossology instance |
287 |
| -
|
288 |
| - API Endpoint: GET /users |
289 |
| -
|
290 |
| - :return: the list of users |
291 |
| - :rtype: list of User |
292 |
| - :raises FossologyApiError: if the REST call failed |
293 |
| - """ |
294 |
| - response = self.session.get(f"{self.api}/users") |
295 |
| - if response.status_code == 200: |
296 |
| - users_list = list() |
297 |
| - for user in response.json(): |
298 |
| - if user.get("name") == "Default User": |
299 |
| - continue |
300 |
| - if user.get("email"): |
301 |
| - foss_user = User.from_json(user) |
302 |
| - agents = user.get("agents") |
303 |
| - if agents: |
304 |
| - foss_user.agents = Agents.from_json(agents) |
305 |
| - users_list.append(foss_user) |
306 |
| - return users_list |
307 |
| - else: |
308 |
| - description = f"Unable to get a list of users from {self.host}" |
309 |
| - raise FossologyApiError(description, response) |
310 |
| - |
311 |
| - def delete_user(self, user): |
312 |
| - """Delete a Fossology user. |
313 |
| -
|
314 |
| - API Endpoint: DELETE /users/{id} |
315 |
| -
|
316 |
| - :param user: the user to be deleted |
317 |
| - :type user: User |
318 |
| - :raises FossologyApiError: if the REST call failed |
319 |
| - """ |
320 |
| - response = self.session.delete(f"{self.api}/users/{user.id}") |
321 |
| - |
322 |
| - if response.status_code == 202: |
323 |
| - return |
324 |
| - else: |
325 |
| - description = f"Error while deleting user {user.name} ({user.id})" |
326 |
| - raise FossologyApiError(description, response) |
327 |
| - |
328 |
| - def search( |
329 |
| - self, |
330 |
| - searchType: SearchTypes = SearchTypes.ALLFILES, |
331 |
| - upload: Upload = None, |
332 |
| - filename: str = None, |
333 |
| - tag: str = None, |
334 |
| - filesizemin: int = None, |
335 |
| - filesizemax: int = None, |
336 |
| - license: str = None, |
337 |
| - copyright: str = None, |
338 |
| - group: str = None, |
339 |
| - ): |
340 |
| - """Search for a specific file |
341 |
| -
|
342 |
| - API Endpoint: GET /search |
343 |
| -
|
344 |
| - :param searchType: Limit search to: directory, allfiles (default), containers |
345 |
| - :param upload: Limit search to a specific upload |
346 |
| - :param filename: Filename to find, can contain % as wild-card |
347 |
| - :param tag: tag to find |
348 |
| - :param filesizemin: Min filesize in bytes |
349 |
| - :param filesizemax: Max filesize in bytes |
350 |
| - :param license: License search filter |
351 |
| - :param copyright: Copyright search filter |
352 |
| - :param group: the group name to choose while performing search (default: None) |
353 |
| - :type searchType: one of SearchTypes Enum |
354 |
| - :type upload: Upload |
355 |
| - :type filename: string |
356 |
| - :type tag: string |
357 |
| - :type filesizemin: int |
358 |
| - :type filesizemax: int |
359 |
| - :type license: string |
360 |
| - :type copyright: string |
361 |
| - :type group: string |
362 |
| - :return: list of items corresponding to the search criteria |
363 |
| - :rtype: JSON |
364 |
| - :raises FossologyApiError: if the REST call failed |
365 |
| - :raises AuthorizationError: if the user can't access the group |
366 |
| - """ |
367 |
| - headers = search_headers( |
368 |
| - searchType, |
369 |
| - upload, |
370 |
| - filename, |
371 |
| - tag, |
372 |
| - filesizemin, |
373 |
| - filesizemax, |
374 |
| - license, |
375 |
| - copyright, |
376 |
| - group, |
377 |
| - ) |
378 |
| - response = self.session.get(f"{self.api}/search", headers=headers) |
379 |
| - |
380 |
| - if response.status_code == 200: |
381 |
| - return response.json() |
382 |
| - |
383 |
| - elif response.status_code == 403: |
384 |
| - description = f"Searching {get_options(group)}not authorized" |
385 |
| - raise AuthorizationError(description, response) |
386 |
| - |
387 |
| - else: |
388 |
| - description = "Unable to get a result with the given search criteria" |
389 |
| - raise FossologyApiError(description, response) |
390 |
| - |
391 |
| - def filesearch( |
392 |
| - self, |
393 |
| - filelist: List = [], |
394 |
| - group: str = None, |
395 |
| - ): |
396 |
| - """Search for files from hash sum |
397 |
| -
|
398 |
| - API Endpoint: POST /filesearch |
399 |
| -
|
400 |
| - The response does not generate Python objects yet, the plain JSON data is simply returned. |
401 |
| -
|
402 |
| - :param filelist: the list of files (or containers) hashes to search for (default: []) |
403 |
| - :param group: the group name to choose while performing search (default: None) |
404 |
| - :type filelist: list |
405 |
| - :return: list of items corresponding to the search criteria |
406 |
| - :type group: string |
407 |
| - :rtype: JSON |
408 |
| - :raises FossologyApiError: if the REST call failed |
409 |
| - :raises AuthorizationError: if the user can't access the group |
410 |
| - """ |
411 |
| - if versiontuple(self.version) <= versiontuple("1.0.16"): |
412 |
| - description = f"Endpoint /filesearch is not supported by your Fossology API version {self.version}" |
413 |
| - raise FossologyUnsupported(description) |
414 |
| - |
415 |
| - headers = {} |
416 |
| - if group: |
417 |
| - headers["groupName"] = group |
418 |
| - |
419 |
| - response = self.session.post( |
420 |
| - f"{self.api}/filesearch", headers=headers, json=filelist |
421 |
| - ) |
422 |
| - |
423 |
| - if response.status_code == 200: |
424 |
| - all_files = [] |
425 |
| - for hash_file in response.json(): |
426 |
| - if hash_file.get("findings"): |
427 |
| - all_files.append(File.from_json(hash_file)) |
428 |
| - else: |
429 |
| - return "Unable to get a result with the given filesearch criteria" |
430 |
| - return all_files |
431 |
| - |
432 |
| - elif response.status_code == 403: |
433 |
| - description = f"Searching {get_options(group)}not authorized" |
434 |
| - raise AuthorizationError(description, response) |
435 |
| - |
436 |
| - else: |
437 |
| - description = "Unable to get a result with the given filesearch criteria" |
438 |
| - raise FossologyApiError(description, response) |
0 commit comments