Fix #3878: Backend : Getting 500 internal server error for follows activity feed filter (#3927)

This commit is contained in:
Vivek Ratnavel Subramanian 2022-04-07 23:14:10 -07:00 committed by GitHub
parent e33d64467a
commit b45ed2c8de
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 68 additions and 12 deletions

View File

@ -654,6 +654,7 @@ public interface CollectionDAO {
+ "LIMIT :limit")
List<String> listThreadsByFollowsBefore(
@Bind("userId") String userId,
@BindList("teamIds") List<String> teamIds,
@Bind("limit") int limit,
@Bind("before") long before,
@Bind("resolved") boolean resolved,
@ -668,6 +669,7 @@ public interface CollectionDAO {
+ "LIMIT :limit")
List<String> listThreadsByFollowsAfter(
@Bind("userId") String userId,
@BindList("teamIds") List<String> teamIds,
@Bind("limit") int limit,
@Bind("after") long after,
@Bind("resolved") boolean resolved,
@ -679,7 +681,10 @@ public interface CollectionDAO {
+ "((fromEntity='user' AND fromId= :userId) OR "
+ "(fromEntity='team' AND fromId IN (<teamIds>))) AND relation= :relation)")
int listCountThreadsByFollows(
@Bind("userId") String userId, @Bind("resolved") boolean resolved, @Bind("relation") int relation);
@Bind("userId") String userId,
@BindList("teamIds") List<String> teamIds,
@Bind("resolved") boolean resolved,
@Bind("relation") int relation);
@SqlQuery(
"SELECT json FROM thread_entity WHERE updatedAt > :before AND resolved = :resolved AND id in ("

View File

@ -550,13 +550,19 @@ public class FeedRepository {
private FilteredThreads getThreadsByFollows(
String userId, int limit, long time, boolean isResolved, PaginationType paginationType) throws IOException {
List<String> jsons;
List<String> teamIds = getTeamIds(userId);
if (paginationType == PaginationType.BEFORE) {
jsons = dao.feedDAO().listThreadsByFollowsBefore(userId, limit, time, isResolved, Relationship.FOLLOWS.ordinal());
jsons =
dao.feedDAO()
.listThreadsByFollowsBefore(userId, teamIds, limit, time, isResolved, Relationship.FOLLOWS.ordinal());
} else {
jsons = dao.feedDAO().listThreadsByFollowsAfter(userId, limit, time, isResolved, Relationship.FOLLOWS.ordinal());
jsons =
dao.feedDAO()
.listThreadsByFollowsAfter(userId, teamIds, limit, time, isResolved, Relationship.FOLLOWS.ordinal());
}
List<Thread> threads = JsonUtils.readObjects(jsons, Thread.class);
int totalCount = dao.feedDAO().listCountThreadsByFollows(userId, isResolved, Relationship.FOLLOWS.ordinal());
int totalCount =
dao.feedDAO().listCountThreadsByFollows(userId, teamIds, isResolved, Relationship.FOLLOWS.ordinal());
return new FilteredThreads(threads, totalCount);
}

View File

@ -14,6 +14,7 @@
package org.openmetadata.catalog.resources.feeds;
import static javax.ws.rs.core.Response.Status.BAD_REQUEST;
import static javax.ws.rs.core.Response.Status.CREATED;
import static javax.ws.rs.core.Response.Status.FORBIDDEN;
import static javax.ws.rs.core.Response.Status.NOT_FOUND;
import static org.junit.jupiter.api.Assertions.assertEquals;
@ -518,6 +519,31 @@ public class FeedResourceTest extends CatalogApplicationTest {
assertEquals(2, threads.getPaging().getTotal());
}
@Test
void list_threadsWithFollowsFilter() throws HttpResponseException {
// Get the initial thread count of TABLE2
String entityLink = String.format("<#E/table/%s>", TABLE2.getFullyQualifiedName());
int initialThreadCount = listThreads(entityLink, null, AUTH_HEADERS).getPaging().getTotal();
// Create threads
createAndCheck(create().withMessage("Message 1").withAbout(entityLink), ADMIN_AUTH_HEADERS);
createAndCheck(create().withMessage("Message 2").withAbout(entityLink), ADMIN_AUTH_HEADERS);
// Make the USER follow TABLE2
followTable(TABLE2.getId(), USER.getId(), AUTH_HEADERS);
ThreadList threads = listThreadsWithFilter(USER.getId().toString(), FilterType.FOLLOWS.toString(), AUTH_HEADERS);
assertEquals(initialThreadCount + 2, threads.getPaging().getTotal());
assertEquals(initialThreadCount + 2, threads.getData().size());
assertEquals("Message 2", threads.getData().get(0).getMessage());
// Filter by follows for another user should return 0 threads
threads = listThreadsWithFilter(USER2.getId().toString(), FilterType.FOLLOWS.toString(), AUTH_HEADERS);
assertEquals(0, threads.getPaging().getTotal());
assertEquals(0, threads.getData().size());
}
@Test
void list_threadsWithInvalidFilter() {
assertResponse(
@ -679,6 +705,12 @@ public class FeedResourceTest extends CatalogApplicationTest {
return TestUtils.get(target, ThreadList.class, authHeaders);
}
public static void followTable(UUID tableId, UUID userId, Map<String, String> authHeaders)
throws HttpResponseException {
WebTarget target = getResource("tables/" + tableId + "/followers");
TestUtils.put(target, userId.toString(), CREATED, authHeaders);
}
public static ThreadList listThreadsWithFilter(String userId, String filterType, Map<String, String> authHeaders)
throws HttpResponseException {
WebTarget target = getResource("feed");

View File

@ -54,6 +54,7 @@ const jsonData = {
'fetch-data-error': 'Error while fetching data!',
'fetch-database-details-error': 'Error while fetching database details!',
'fetch-database-tables-error': 'Error while fetching database tables!',
'fetch-activity-feed-error': 'Error while fetching activity feeds!',
'fetch-entity-feed-error': 'Error while fetching entity feeds!',
'fetch-entity-feed-count-error': 'Error while fetching entity feed count!',
'fetch-entity-count-error': 'Error while fetching entity count!',

View File

@ -238,11 +238,13 @@ const MyDataPage = () => {
setEntityThread((prevData) => [...prevData, ...data]);
})
.catch(() => {
showToast({
variant: 'error',
body: 'Error while fetching the Activity Feed',
});
.catch((err: AxiosError) => {
handleShowErrorToast(
getErrorText(
err,
jsonData['api-error-messages']['fetch-activity-feed-error']
)
);
})
.finally(() => {
setIsFeedLoading(false);

View File

@ -106,7 +106,17 @@ export const getErrorText = (
value: AxiosError | string,
fallbackText: string
): string => {
return (
(isString(value) ? value : value.response?.data?.message) || fallbackText
);
let errorText;
if (isString(value)) {
return value;
} else {
errorText = value.response?.data?.message;
if (!errorText) {
// if error text is undefined or null or empty, try responseMessage in data
errorText = value.response?.data?.responseMessage;
}
}
// if error text is still empty, return the fallback text
return errorText || fallbackText;
};