Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(api): new endpoint /mySubmissions #2271

Merged
merged 1 commit into from
Feb 26, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,13 @@ public List<ModerationRequest> getRequestsByRequestingUser(User user) throws TEx
return handler.getRequestsByRequestingUser(user.getEmail());
}

@Override
public List<ModerationRequest> getRequestsByRequestingUserWithPagination(User user, PaginationData pageData) throws TException {
assertUser(user);

return handler.getRequestsByRequestingUserWithPagination(user.getEmail(), pageData);
}

@Override
public ClearingRequest getClearingRequestByProjectId(String projectId, User user) throws TException {
assertId(projectId);
Expand Down Expand Up @@ -372,6 +379,12 @@ public Map<String, Long> getCountByModerationState(User user) throws TException
return handler.getCountByModerationState(user.getEmail());
}

@Override
public Map<String, Long> getCountByRequester(User user) throws TException {
assertUser(user);
return handler.getCountByRequester(user.getEmail());
}

@Override
public Map<PaginationData, List<ModerationRequest>> getRequestsByModeratorWithPagination(User user,
PaginationData pageData, boolean open) throws TException {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -148,6 +148,10 @@ public List<ModerationRequest> getRequestsByRequestingUser(String user) {
return repository.getRequestsByRequestingUser(user);
}

public List<ModerationRequest> getRequestsByRequestingUserWithPagination(String user, PaginationData pageData) {
return repository.getRequestsByRequestingUserWithPagination(user, pageData);
}

public ClearingRequest getClearingRequestByProjectId(String projectId, User user) throws SW360Exception {
projectDatabaseHandler.getProjectById(projectId, user); // check if user have READ access to project.
return clearingRequestRepository.getClearingRequestByProjectId(projectId);
Expand Down Expand Up @@ -890,6 +894,10 @@ public Map<String, Long> getCountByModerationState(String moderator) {
return repository.getCountByModerationState(moderator);
}

public Map<String, Long> getCountByRequester(String moderator) {
return repository.getCountByRequester(moderator);
}

public Set<String> getRequestingUserDepts() {
return repository.getRequestingUserDepts();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,19 @@ public class ModerationRequestRepository extends SummaryAwareRepository<Moderati
" }" +
"}";

private static final String COUNTBYREQUESTER = "function(doc) {" +
" if (doc.type == 'moderation') {" +
" emit([doc.requestingUser], null);" +
" }" +
"}";

public ModerationRequestRepository(DatabaseConnectorCloudant db) {
super(ModerationRequest.class, db, new ModerationRequestSummary());
Map<String, MapReduce> views = new HashMap<String, MapReduce>();
views.put("all", createMapReduce(ALL, null));
views.put("byRequestingUsersDeptView", createMapReduce(REQUESTING_USERS_VIEW, null));
views.put("countByModerationState", createMapReduce(COUNTBYMODERATIONSTATE, "_count"));
views.put("countByRequester", createMapReduce(COUNTBYREQUESTER, "_count"));
initStandardDesignDocument(views, db);
createIndex("byModerators", new String[] {"moderators"}, db);
createIndex("byDate", new String[] {"timestamp"}, db);
Expand Down Expand Up @@ -260,6 +267,29 @@ public List<ModerationRequest> getRequestsByRequestingUser(String user) {
return makeSummaryFromFullDocs(SummaryType.SHORT, mrs);
}

public List<ModerationRequest> getRequestsByRequestingUserWithPagination(String user, PaginationData pageData) {
final int rowsPerPage = pageData.getRowsPerPage();
final boolean ascending = pageData.isAscending();
final int skip = pageData.getDisplayStart();
final Selector typeSelector = eq("type", "moderation");
final Selector filterByModeratorSelector = eq("requestingUser", user);
final Selector finalSelector = and(typeSelector, filterByModeratorSelector);
QueryBuilder qb = new QueryBuilder(finalSelector);
qb.limit(rowsPerPage);
qb.skip(skip);
qb.useIndex("byUsers");
qb = ascending ? qb.sort(Sort.asc("timestamp")) : qb.sort(Sort.desc("timestamp"));

List<ModerationRequest> modReqs = Lists.newArrayList();
try {
QueryResult<ModerationRequest> queryResult = getConnector().getQueryResult(qb.build(), ModerationRequest.class);
modReqs = queryResult.getDocs();
} catch (Exception e) {
log.error("Error getting moderation requests", e);
}
return modReqs;
}

public Map<String, Long> getCountByModerationState(String moderator) {
Map<String, Long> countByModerationState = Maps.newHashMap();
List<ComplexKey> keys = prepareKeys(moderator, true);
Expand All @@ -282,6 +312,27 @@ public Map<String, Long> getCountByModerationState(String moderator) {
return countByModerationState;
}

public Map<String, Long> getCountByRequester(String user) {
Map<String, Long> countByModerationState = Maps.newHashMap();

List<ComplexKey> keys = prepareKeys(user, true);
ViewRequest<ComplexKey, Long> countReq = getConnector()
.createQuery(ModerationRequest.class, "countByRequester").newRequest(Key.Type.COMPLEX, Long.class)
.startKey(keys.get(0)).endKey(keys.get(1)).group(true).groupLevel(2).reduce(true).build();
try {
ViewResponse<ComplexKey, Long> response = countReq.getResponse();
if (null != response) {
countByModerationState = response.getRows().stream().collect(Collectors.toMap(key -> {
String json = key.getKey().toJson();
return json.replaceAll("[\\[\\]\"]", "");
}, ViewResponse.Row::getValue));
}
} catch (IOException e) {
log.error("Error getting count of moderation requests based on moderation state", e);
}
return countByModerationState;
}

public Set<String> getRequestingUserDepts() {
Set<String> requestingUserDepts = Sets.newHashSet();
ViewRequest<String, Object> query = getConnector()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@
import org.eclipse.sw360.datahandler.thrift.moderation.ModerationRequest;
import org.eclipse.sw360.datahandler.thrift.packages.Package;
import org.eclipse.sw360.datahandler.thrift.projects.Project;
import org.eclipse.sw360.datahandler.thrift.search.SearchResult;
import org.eclipse.sw360.datahandler.thrift.users.User;
import org.eclipse.sw360.datahandler.thrift.vendors.Vendor;
import org.eclipse.sw360.datahandler.thrift.search.SearchResult;
import org.eclipse.sw360.datahandler.thrift.vulnerabilities.VulnerabilityDTO;
import org.eclipse.sw360.datahandler.thrift.vulnerabilities.Vulnerability;
import org.eclipse.sw360.datahandler.thrift.vulnerabilities.VulnerabilityDTO;

public class ResourceComparatorGenerator<T> {

Expand Down Expand Up @@ -166,6 +166,10 @@ private static Map<ModerationRequest._Fields, Comparator<ModerationRequest>> gen
Comparator.comparing(ModerationRequest::getRequestingUser, Comparator.nullsFirst(String.CASE_INSENSITIVE_ORDER)));
moderationRequestMap.put(ModerationRequest._Fields.DOCUMENT_TYPE,
Comparator.comparing(c -> Optional.ofNullable(c.getDocumentType()).map(Object::toString).orElse(null), Comparator.nullsFirst(String.CASE_INSENSITIVE_ORDER)));
moderationRequestMap.put(ModerationRequest._Fields.DOCUMENT_NAME,
Comparator.comparing(ModerationRequest::getDocumentName, Comparator.nullsFirst(String.CASE_INSENSITIVE_ORDER)));
moderationRequestMap.put(ModerationRequest._Fields.MODERATION_STATE,
Comparator.comparing(c -> Optional.ofNullable(c.getModerationState()).map(Object::toString).orElse(null), Comparator.nullsFirst(String.CASE_INSENSITIVE_ORDER)));
return Collections.unmodifiableMap(moderationRequestMap);
}

Expand Down Expand Up @@ -309,6 +313,15 @@ public Comparator<T> generateComparator(String type, List<String> properties) th
}
}
return generateReleaseEccComparatorWithFields(type, releaseFields, eccInfoFields);
case SW360Constants.TYPE_MODERATION:
List<ModerationRequest._Fields> modFields = new ArrayList<>();
for (String property : properties) {
ModerationRequest._Fields field = ModerationRequest._Fields.findByName(property);
if (field != null) {
modFields.add(field);
}
}
return generateModerationRequestComparatorWithFields(type, modFields);
default:
throw new ResourceClassNotFoundException("No comparator for resource class with name " + type);
}
Expand Down Expand Up @@ -414,6 +427,16 @@ public Comparator<T> generateVulComparatorWithFields(String type, List<Vulnerabi
}
}

public Comparator<T> generateModerationRequestComparatorWithFields(
String type, List<ModerationRequest._Fields> fields) throws ResourceClassNotFoundException {
switch (type) {
case SW360Constants.TYPE_MODERATION:
return (Comparator<T>) moderationComparator(fields);
default:
throw new ResourceClassNotFoundException("No comparator for resource class with name " + type);
}
}


private Comparator<Component> componentComparator(List<Component._Fields> fields) {
Comparator<Component> comparator = Comparator.comparing(x -> true);
Expand Down Expand Up @@ -560,6 +583,18 @@ private Comparator<Vulnerability> vulnComparator(List<Vulnerability._Fields> fie
return comparator;
}

private Comparator<ModerationRequest> moderationComparator(List<ModerationRequest._Fields> fields) {
Comparator<ModerationRequest> comparator = Comparator.comparing(x -> true);
for (ModerationRequest._Fields field : fields) {
Comparator<ModerationRequest> fieldComparator = moderationRequestMap.get(field);
if (fieldComparator != null) {
comparator = comparator.thenComparing(fieldComparator);
}
}
comparator = comparator.thenComparing(defaultModerationRequestComparator());
return comparator;
}

private Comparator<Component> defaultComponentComparator() {
return componentMap.get(Component._Fields.NAME);
}
Expand Down
10 changes: 10 additions & 0 deletions libraries/datahandler/src/main/thrift/moderation.thrift
Original file line number Diff line number Diff line change
Expand Up @@ -269,6 +269,11 @@ service ModerationService {
**/
list<ModerationRequest> getRequestsByRequestingUser(1: User user);

/**
* get list of moderation requests where user is requesting user, paginated
**/
list<ModerationRequest> getRequestsByRequestingUserWithPagination(1: User user, 2: PaginationData pageData);

/**
* delete moderation request specified by id if user is requesting user of moderation request
**/
Expand Down Expand Up @@ -334,6 +339,11 @@ service ModerationService {
**/
map<string, i64> getCountByModerationState(1: User user);

/**
* get count of moderation requests by a requester
**/
map<string, i64> getCountByRequester(1: User user);

/**
* get requesting users departments
**/
Expand Down
17 changes: 17 additions & 0 deletions rest/resource-server/src/docs/asciidoc/moderationRequests.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,20 @@ include::{snippets}/should_document_get_moderationrequests_assign/curl-request.a

===== Example response
include::{snippets}/should_document_get_moderationrequests_assign/http-response.adoc[]

[[resources-moderationRequest-submission]]
==== Get Submitted Moderation Requests

A `GET` will pull <<resources-moderationRequest, ModerationRequest>> which are created by the requesting user.

===== Request parameter
include::{snippets}/should_document_get_moderationrequests_submission/request-parameters.adoc[]

===== Response structure
include::{snippets}/should_document_get_moderationrequests_submission/response-fields.adoc[]

===== Example request
include::{snippets}/should_document_get_moderationrequests_submission/curl-request.adoc[]

===== Example response
include::{snippets}/should_document_get_moderationrequests_submission/http-response.adoc[]
Original file line number Diff line number Diff line change
Expand Up @@ -101,22 +101,14 @@ public ResponseEntity<CollectionModel<ModerationRequest>> getModerationRequests(
) throws TException, ResourceClassNotFoundException, URISyntaxException {
User sw360User = restControllerHelper.getSw360UserFromAuthentication();
List<ModerationRequest> moderationRequests = sw360ModerationRequestService.getRequestsByModerator(sw360User, pageable);
int totalCount = (int) sw360ModerationRequestService.getTotalCountOfRequests(sw360User);
PaginationResult<ModerationRequest> paginationResult = restControllerHelper.paginationResultFromPaginatedList(request,
pageable, moderationRequests, SW360Constants.TYPE_MODERATION, totalCount);

List<EntityModel<ModerationRequest>> moderationRequestResources = new ArrayList<>();
paginationResult.getResources().forEach(m -> addModerationRequest(m, allDetails, moderationRequestResources));

CollectionModel<ModerationRequest> resources;
if (moderationRequestResources.isEmpty()) {
resources = restControllerHelper.emptyPageResource(ModerationRequest.class, paginationResult);
} else {
resources = restControllerHelper.generatePagesResource(paginationResult, moderationRequestResources);
}
Map<PaginationData, List<ModerationRequest>> modRequestsWithPageData =
new HashMap<>();
PaginationData paginationData = new PaginationData();
paginationData.setTotalRowCount(sw360ModerationRequestService.getTotalCountOfRequests(sw360User));
modRequestsWithPageData.put(paginationData, moderationRequests);

HttpStatus status = resources == null ? HttpStatus.NO_CONTENT : HttpStatus.OK;
return new ResponseEntity<>(resources, status);
return getModerationResponseEntity(pageable, request, allDetails, modRequestsWithPageData);
}

@Operation(
Expand Down Expand Up @@ -166,27 +158,7 @@ public ResponseEntity<CollectionModel<ModerationRequest>> getModerationRequestsB
boolean stateOpen = stateOptions.get(0).equalsIgnoreCase(state);
Map<PaginationData, List<ModerationRequest>> modRequestsWithPageData =
sw360ModerationRequestService.getRequestsByState(sw360User, pageable, stateOpen, allDetails);
List<ModerationRequest> moderationRequests = new ArrayList<>();
int totalCount = 0;
if (!CommonUtils.isNullOrEmptyMap(modRequestsWithPageData)) {
PaginationData paginationData = modRequestsWithPageData.keySet().iterator().next();
moderationRequests = modRequestsWithPageData.get(paginationData);
totalCount = (int) paginationData.getTotalRowCount();
}

PaginationResult<ModerationRequest> paginationResult = restControllerHelper.paginationResultFromPaginatedList(request,
pageable, moderationRequests, SW360Constants.TYPE_MODERATION, totalCount);

List<EntityModel<ModerationRequest>> moderationRequestResources = new ArrayList<>();
paginationResult.getResources().forEach(m -> addModerationRequest(m, allDetails, moderationRequestResources));

CollectionModel<ModerationRequest> resources;
if (moderationRequestResources.isEmpty()) {
resources = restControllerHelper.emptyPageResource(ModerationRequest.class, paginationResult);
} else {
resources = restControllerHelper.generatePagesResource(paginationResult, moderationRequestResources);
}
return new ResponseEntity<>(resources, HttpStatus.OK);
return getModerationResponseEntity(pageable, request, allDetails, modRequestsWithPageData);
}

private @NotNull HalResource<ModerationRequest> createHalModerationRequestWithAllDetails(
Expand Down Expand Up @@ -317,4 +289,57 @@ private void addModerationRequest(ModerationRequest moderationRequest, boolean a
}
moderationRequestResources.add(embeddedModerationRequestResource);
}

@Operation(
summary = "Get my submissions.",
description = "Get moderation requests submitted by the user. The responses are sortable by fields " +
"\"timestamp\", \"documentName\" and \"moderationState\".",
tags = {"Moderation Requests"}
)
@GetMapping(value = MODERATION_REQUEST_URL + "/mySubmissions")
public ResponseEntity<CollectionModel<ModerationRequest>> getSubmissions(
Pageable pageable, HttpServletRequest request
) throws TException, URISyntaxException, ResourceClassNotFoundException {
User sw360User = restControllerHelper.getSw360UserFromAuthentication();
Map<PaginationData, List<ModerationRequest>> modRequestsWithPageData =
sw360ModerationRequestService.getRequestsByRequestingUser(sw360User, pageable);
return getModerationResponseEntity(pageable, request, false, modRequestsWithPageData);
}

/**
* Generate a Response Entity for paginated moderation request list.
* @param pageable Pageable request
* @param request HTTP Request
* @param allDetails Request with allDetails?
* @param modRequestsWithPageData Map of pagination data and moderation request list
* @return Returns the Response Entity with pagination data.
*/
@NotNull
private ResponseEntity<CollectionModel<ModerationRequest>> getModerationResponseEntity(
Pageable pageable, HttpServletRequest request, boolean allDetails,
Map<PaginationData, List<ModerationRequest>> modRequestsWithPageData
) throws ResourceClassNotFoundException, URISyntaxException {
List<ModerationRequest> moderationRequests = new ArrayList<>();
int totalCount = 0;
if (!CommonUtils.isNullOrEmptyMap(modRequestsWithPageData)) {
PaginationData paginationData = modRequestsWithPageData.keySet().iterator().next();
moderationRequests = modRequestsWithPageData.get(paginationData);
totalCount = (int) paginationData.getTotalRowCount();
}

PaginationResult<ModerationRequest> paginationResult = restControllerHelper.paginationResultFromPaginatedList(
request, pageable, moderationRequests, SW360Constants.TYPE_MODERATION, totalCount);

List<EntityModel<ModerationRequest>> moderationRequestResources = new ArrayList<>();
paginationResult.getResources().forEach(m -> addModerationRequest(m, allDetails, moderationRequestResources));

CollectionModel<ModerationRequest> resources;
if (moderationRequestResources.isEmpty()) {
resources = restControllerHelper.emptyPageResource(ModerationRequest.class, paginationResult);
} else {
resources = restControllerHelper.generatePagesResource(paginationResult, moderationRequestResources);
}
HttpStatus status = resources == null ? HttpStatus.NO_CONTENT : HttpStatus.OK;
return new ResponseEntity<>(resources, status);
}
}
Loading
Loading