Skip to content

Commit d6b1b38

Browse files
authored
Merge pull request #103 from fossology/fix/uploadType
Fix/upload type required by API version 1.5.1
2 parents edb3f71 + 3b19555 commit d6b1b38

File tree

13 files changed

+1155
-786
lines changed

13 files changed

+1155
-786
lines changed

.github/workflows/fossologytests.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ on:
1010

1111
jobs:
1212
test-latest:
13-
name: Integration Tests (latest Fossology)
13+
name: Integration Tests (latest Fossology - 4.2.1)
1414
runs-on: ubuntu-latest
1515

1616
container:
@@ -20,7 +20,7 @@ jobs:
2020

2121
services:
2222
fossology:
23-
image: fossology/fossology:latest
23+
image: fossology/fossology:4.2.1
2424
ports:
2525
- 8081:80
2626
volumes:

fossology/__init__.py

Lines changed: 5 additions & 233 deletions
Original file line numberDiff line numberDiff line change
@@ -4,73 +4,24 @@
44
import logging
55
import re
66
from datetime import date, timedelta
7-
from typing import Dict, List
87

98
import requests
109

11-
from fossology.exceptions import (
12-
AuthenticationError,
13-
AuthorizationError,
14-
FossologyApiError,
15-
FossologyUnsupported,
16-
)
10+
from fossology.exceptions import AuthenticationError, FossologyApiError
1711
from fossology.folders import Folders
1812
from fossology.groups import Groups
1913
from fossology.jobs import Jobs
2014
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
3216
from fossology.report import Report
17+
from fossology.search import Search
3318
from fossology.uploads import Uploads
19+
from fossology.users import Users
3420

3521
logger = logging.getLogger(__name__)
3622
logger.setLevel(logging.DEBUG)
3723

3824

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-
7425
def fossology_token(
7526
url, username, password, token_name, token_scope=TokenScope.READ, token_expire=None
7627
):
@@ -128,7 +79,7 @@ def fossology_token(
12879
exit(f"Server {url} does not seem to be running or is unreachable: {error}")
12980

13081

131-
class Fossology(Folders, Groups, LicenseEndpoint, Uploads, Jobs, Report):
82+
class Fossology(Folders, Groups, LicenseEndpoint, Uploads, Jobs, Report, Users, Search):
13283

13384
"""Main Fossology API class
13485
@@ -257,182 +208,3 @@ def get_health(self) -> ApiInfo:
257208
else:
258209
description = "Error while getting health info"
259210
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)

fossology/groups.py

Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66

77
import fossology
88
from fossology.exceptions import FossologyApiError, FossologyUnsupported
9-
from fossology.obj import Group
9+
from fossology.obj import Group, MemberPerm, UserGroupMember
1010

1111
logger = logging.getLogger(__name__)
1212
logger.setLevel(logging.DEBUG)
@@ -40,6 +40,31 @@ def list_groups(self) -> List:
4040
description = f"Unable to get a list of groups for {self.user.name}"
4141
raise FossologyApiError(description, response)
4242

43+
def list_group_members(self, group_id: int) -> List:
44+
"""Get the list of members for a given group (accessible groups for user, all groups for admin)
45+
46+
API Endpoint: GET /groups/{id}/members
47+
48+
:return: a list of members
49+
:rtype: list()
50+
:raises FossologyApiError: if the REST call failed
51+
"""
52+
if fossology.versiontuple(self.version) < fossology.versiontuple("1.5.0"):
53+
description = f"Endpoint /groups/id/members is not supported by your Fossology API version {self.version}"
54+
raise FossologyUnsupported(description)
55+
56+
response = self.session.get(f"{self.api}/groups/{group_id}/members")
57+
if response.status_code == 200:
58+
members_list = []
59+
response_list = response.json()
60+
for member in response_list:
61+
single_member = UserGroupMember.from_json(member)
62+
members_list.append(single_member)
63+
return members_list
64+
else:
65+
description = f"Unable to get a list of members for group {group_id}"
66+
raise FossologyApiError(description, response)
67+
4368
def create_group(self, name):
4469
"""Create a group
4570
@@ -62,3 +87,38 @@ def create_group(self, name):
6287
else:
6388
description = f"Group {name} already exists, failed to create group or no group name provided"
6489
raise FossologyApiError(description, response)
90+
91+
def add_group_member(
92+
self, group_id: int, user_id: int, perm: MemberPerm = MemberPerm.USER
93+
):
94+
"""Add a user to a group
95+
96+
API Endpoint: POST /groups/{group_id}/user/{user_id}
97+
98+
:param group_id: the id of the group
99+
:param user_id: the id of the user
100+
:param perm: the permission level for the user
101+
:type group_id: int
102+
:type user_id: int
103+
:type perm: MemberPerm
104+
:raises FossologyApiError: if the REST call failed
105+
"""
106+
if fossology.versiontuple(self.version) < fossology.versiontuple("1.5.0"):
107+
description = f"Endpoint /groups/id/user/id is not supported by your Fossology API version {self.version}"
108+
raise FossologyUnsupported(description)
109+
110+
data = dict()
111+
data["perm"] = perm.value
112+
response = self.session.post(
113+
f"{self.api}/groups/{group_id}/user/{user_id}", json=data
114+
)
115+
if response.status_code == 200:
116+
logger.info(f"User {user_id} has been added to group {group_id}.")
117+
elif response.status_code == 400:
118+
logger.info(f"User {user_id} is already a member of group {group_id}.")
119+
else:
120+
description = (
121+
f"An error occurred while adding user {user_id} to group {group_id}"
122+
)
123+
raise FossologyApiError(description, response)
124+
return

0 commit comments

Comments
 (0)