A list of all posts in a topic is stored in an object for quick lookup. This is used when switching between topics to get the list of posts in that topic. When filters change the list of posts in a topics is updated and this is picked up by the UI. If changing filters when browsing a topic results in an empty result, this would cause the original list of topics for that topic to be retained, causing the filter to simply not apply. This commit fixes that by resetting the post list in that case.
204 lines
5.1 KiB
JavaScript
204 lines
5.1 KiB
JavaScript
/* eslint-disable import/prefer-default-export */
|
|
import snakeCase from 'lodash.snakecase';
|
|
|
|
import { ensureConfig, getConfig, snakeCaseObject } from '@edx/frontend-platform';
|
|
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
|
|
|
ensureConfig([
|
|
'LMS_BASE_URL',
|
|
], 'Posts API service');
|
|
|
|
const apiBaseUrl = getConfig().LMS_BASE_URL;
|
|
|
|
export const threadsApiUrl = `${apiBaseUrl}/api/discussion/v1/threads/`;
|
|
export const coursesApiUrl = `${apiBaseUrl}/api/discussion/v1/courses/`;
|
|
|
|
/**
|
|
* Fetches all the threads in the given course and topic.
|
|
* @param {string} courseId
|
|
* @param {string} author
|
|
* @param {[string]} topicIds List of topics to limit threads to
|
|
* @param {number} page
|
|
* @param {number} pageSize
|
|
* @param {string} textSearch A search string to match.
|
|
* @param {ThreadOrdering} orderBy The results wil be sorted on this basis.
|
|
* @param {boolean} following If true, only threads followed by the current user will be returned.
|
|
* @param {boolean} flagged If true, only threads that have been reported will be returned.
|
|
* @param {string} threadType Can be 'discussion' or 'question'.
|
|
* @param {ThreadViewStatus} view Set to "unread" on "unanswered" to filter to only those statuses.
|
|
* @param {boolean} countFlagged If true, abuseFlaggedCount will be available.
|
|
* @param {number} cohort
|
|
* @returns {Promise<{}>}
|
|
*/
|
|
export async function getThreads(
|
|
courseId, {
|
|
topicIds,
|
|
page,
|
|
pageSize,
|
|
textSearch,
|
|
orderBy,
|
|
following,
|
|
view,
|
|
author,
|
|
flagged,
|
|
threadType,
|
|
countFlagged,
|
|
cohort,
|
|
} = {},
|
|
) {
|
|
const params = snakeCaseObject({
|
|
courseId,
|
|
page,
|
|
pageSize,
|
|
topicId: topicIds && topicIds.join(','),
|
|
textSearch,
|
|
threadType,
|
|
orderBy: snakeCase(orderBy),
|
|
following,
|
|
view,
|
|
requestedFields: 'profile_image',
|
|
author,
|
|
flagged,
|
|
countFlagged,
|
|
groupId: cohort,
|
|
});
|
|
const { data } = await getAuthenticatedHttpClient().get(threadsApiUrl, { params });
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* Fetches a single thread.
|
|
* @param {string} threadId
|
|
* @returns {Promise<{}>}
|
|
*/
|
|
export async function getThread(threadId) {
|
|
const params = { requested_fields: 'profile_image' };
|
|
const url = `${threadsApiUrl}${threadId}/`;
|
|
const { data } = await getAuthenticatedHttpClient().get(url, { params });
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* Posts a new thread.
|
|
* @param {string} courseId
|
|
* @param {string} topicId
|
|
* @param {ThreadType} type The thread's type (either "question" or "discussion")
|
|
* @param {string} title
|
|
* @param {string} content
|
|
* @param {number} cohort
|
|
* @param {boolean} following Follow the thread after creating
|
|
* @param {boolean} anonymous Should the thread be anonymous to all users
|
|
* @param {boolean} anonymousToPeers Should the thread be anonymous to peers
|
|
* @returns {Promise<{}>}
|
|
*/
|
|
export async function postThread(
|
|
courseId,
|
|
topicId,
|
|
type,
|
|
title,
|
|
content,
|
|
{
|
|
following,
|
|
cohort,
|
|
anonymous,
|
|
anonymousToPeers,
|
|
} = {},
|
|
) {
|
|
const postData = snakeCaseObject({
|
|
courseId,
|
|
topicId,
|
|
type,
|
|
title,
|
|
raw_body: content,
|
|
following,
|
|
anonymous,
|
|
anonymousToPeers,
|
|
groupId: cohort,
|
|
});
|
|
|
|
const { data } = await getAuthenticatedHttpClient()
|
|
.post(threadsApiUrl, postData);
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* Updates an existing thread.
|
|
* @param {string} threadId
|
|
* @param {string} topicId
|
|
* @param {ThreadType} type The thread's type (either "question" or "discussion")
|
|
* @param {string} title
|
|
* @param {string} content
|
|
* @param {boolean} flagged
|
|
* @param {boolean} voted
|
|
* @param {boolean} read
|
|
* @param {boolean} following
|
|
* @param {boolean} closed
|
|
* @param {boolean} pinned
|
|
* @param {string} editReasonCode
|
|
* @param {string} closeReasonCode
|
|
* @returns {Promise<{}>}
|
|
*/
|
|
export async function updateThread(threadId, {
|
|
flagged,
|
|
voted,
|
|
read,
|
|
topicId,
|
|
type,
|
|
title,
|
|
content,
|
|
following,
|
|
closed,
|
|
pinned,
|
|
editReasonCode,
|
|
closeReasonCode,
|
|
} = {}) {
|
|
const url = `${threadsApiUrl}${threadId}/`;
|
|
const patchData = snakeCaseObject({
|
|
topicId,
|
|
abuse_flagged: flagged,
|
|
voted,
|
|
read,
|
|
type,
|
|
title,
|
|
raw_body: content,
|
|
following,
|
|
closed,
|
|
pinned,
|
|
editReasonCode,
|
|
closeReasonCode,
|
|
});
|
|
const { data } = await getAuthenticatedHttpClient()
|
|
.patch(url, patchData, { headers: { 'Content-Type': 'application/merge-patch+json' } });
|
|
return data;
|
|
}
|
|
|
|
/**
|
|
* Deletes a thread.
|
|
* @param {string} threadId
|
|
*/
|
|
export async function deleteThread(threadId) {
|
|
const url = `${threadsApiUrl}${threadId}/`;
|
|
await getAuthenticatedHttpClient()
|
|
.delete(url);
|
|
}
|
|
|
|
/**
|
|
* Upload a file.
|
|
* @param {Blob} blob The file body
|
|
* @param {string} filename
|
|
* @param {string} courseId
|
|
* @param {string} threadKey
|
|
* @returns {Promise<{ location: string }>}
|
|
*/
|
|
export async function uploadFile(blob, filename, courseId, threadKey) {
|
|
const uploadUrl = `${coursesApiUrl}${courseId}/upload`;
|
|
const formData = new FormData();
|
|
formData.append('thread_key', threadKey);
|
|
formData.append('uploaded_file', blob, filename);
|
|
const { data } = await getAuthenticatedHttpClient().post(uploadUrl, formData);
|
|
if (data.developer_message) {
|
|
throw new Error(data.developer_message);
|
|
}
|
|
return data;
|
|
}
|