Skip to content

Commit

Permalink
Add search exam page, fix dates handling.
Browse files Browse the repository at this point in the history
Signed-off-by: Aliwoto <[email protected]>
  • Loading branch information
ALiwoto committed Aug 24, 2024
1 parent 73a6daa commit 369f1c2
Show file tree
Hide file tree
Showing 12 changed files with 661 additions and 161 deletions.
3 changes: 2 additions & 1 deletion src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import SearchCoursePage from './pages/searchCoursePage';
import CreateExamPage from './pages/createExamPage';
import { switchAppTranslation } from './translations/translationSwitcher';
import ExamInfoPage from './pages/examInfoPage';
import SearchExamPage from './pages/searchExamPage';

const App: React.FC = () => {
const [isLoggedIn, setIsLoggedIn] = useState<boolean>(apiClient.isLoggedIn());
Expand Down Expand Up @@ -124,7 +125,7 @@ const App: React.FC = () => {
/>
<Route
path="/searchExam"
element={apiClient.canSearchTopics() ? <SearchTopicPage /> : <Navigate to="/dashboard" />}
element={apiClient.canSearchTopics() ? <SearchExamPage /> : <Navigate to="/dashboard" />}
/>
<Route path="*" element={<Navigate to={isLoggedIn ? "/dashboard" : "/login"} />} />
</Routes>
Expand Down
220 changes: 216 additions & 4 deletions src/api/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,8 @@ export const APIErrorCode = {
ErrCodeAccountAlreadyConfirmed: 2152,
ErrCodeEmailAlreadyExists: 2153,
ErrCodeTopicNameExists: 2154,
ErrCodeTopicNotFound: 2155
ErrCodeTopicNotFound: 2155,
ErrCodeBodyTooLong: 2156
} as const;

export type APIErrorCode = typeof APIErrorCode[keyof typeof APIErrorCode];
Expand Down Expand Up @@ -630,7 +631,7 @@ export interface CreateExamData {
* @type {number}
* @memberof CreateExamData
*/
'course_id'?: number;
'course_id': number;
/**
*
* @type {number}
Expand All @@ -648,13 +649,13 @@ export interface CreateExamData {
* @type {string}
* @memberof CreateExamData
*/
'exam_description'?: string;
'exam_description': string;
/**
*
* @type {string}
* @memberof CreateExamData
*/
'exam_title'?: string;
'exam_title': string;
/**
*
* @type {boolean}
Expand Down Expand Up @@ -2471,6 +2472,69 @@ export interface SearchCourseV1200Response {
*/
'success'?: boolean;
}
/**
*
* @export
* @interface SearchExamData
*/
export interface SearchExamData {
/**
*
* @type {number}
* @memberof SearchExamData
*/
'limit': number;
/**
*
* @type {number}
* @memberof SearchExamData
*/
'offset': number;
/**
*
* @type {string}
* @memberof SearchExamData
*/
'search_query': string;
}
/**
*
* @export
* @interface SearchExamResult
*/
export interface SearchExamResult {
/**
*
* @type {Array<SearchedExamInfo>}
* @memberof SearchExamResult
*/
'exams'?: Array<SearchedExamInfo>;
}
/**
*
* @export
* @interface SearchExamV1200Response
*/
export interface SearchExamV1200Response {
/**
*
* @type {EndpointError}
* @memberof SearchExamV1200Response
*/
'error'?: EndpointError;
/**
*
* @type {SearchExamResult}
* @memberof SearchExamV1200Response
*/
'result'?: SearchExamResult;
/**
*
* @type {boolean}
* @memberof SearchExamV1200Response
*/
'success'?: boolean;
}
/**
*
* @export
Expand Down Expand Up @@ -2628,6 +2692,73 @@ export interface SearchedCourseInfo {
*/
'topic_id'?: number;
}
/**
*
* @export
* @interface SearchedExamInfo
*/
export interface SearchedExamInfo {
/**
*
* @type {number}
* @memberof SearchedExamInfo
*/
'course_id'?: number;
/**
*
* @type {string}
* @memberof SearchedExamInfo
*/
'created_at'?: string;
/**
*
* @type {string}
* @memberof SearchedExamInfo
*/
'created_by'?: string;
/**
*
* @type {number}
* @memberof SearchedExamInfo
*/
'duration'?: number;
/**
*
* @type {string}
* @memberof SearchedExamInfo
*/
'exam_date'?: string;
/**
*
* @type {string}
* @memberof SearchedExamInfo
*/
'exam_description'?: string;
/**
*
* @type {number}
* @memberof SearchedExamInfo
*/
'exam_id'?: number;
/**
*
* @type {string}
* @memberof SearchedExamInfo
*/
'exam_title'?: string;
/**
*
* @type {boolean}
* @memberof SearchedExamInfo
*/
'is_public'?: boolean;
/**
*
* @type {string}
* @memberof SearchedExamInfo
*/
'price'?: string;
}
/**
*
* @export
Expand Down Expand Up @@ -3866,6 +3997,49 @@ export const ExamApiAxiosParamCreator = function (configuration?: Configuration)
options: localVarRequestOptions,
};
},
/**
* Allows the user to search exams.
* @summary Search exams
* @param {string} authorization Authorization token
* @param {SearchExamData} data Data needed to search exams
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
searchExamV1: async (authorization: string, data: SearchExamData, options: RawAxiosRequestConfig = {}): Promise<RequestArgs> => {
// verify required parameter 'authorization' is not null or undefined
assertParamExists('searchExamV1', 'authorization', authorization)
// verify required parameter 'data' is not null or undefined
assertParamExists('searchExamV1', 'data', data)
const localVarPath = `/api/v1/exam/search`;
// use dummy base URL string because the URL constructor only accepts absolute URLs.
const localVarUrlObj = new URL(localVarPath, DUMMY_BASE_URL);
let baseOptions;
if (configuration) {
baseOptions = configuration.baseOptions;
}

const localVarRequestOptions = { method: 'POST', ...baseOptions, ...options};
const localVarHeaderParameter = {} as any;
const localVarQueryParameter = {} as any;

if (authorization != null) {
localVarHeaderParameter['Authorization'] = String(authorization);
}



localVarHeaderParameter['Content-Type'] = 'application/json';

setSearchParams(localVarUrlObj, localVarQueryParameter);
let headersFromBaseOptions = baseOptions && baseOptions.headers ? baseOptions.headers : {};
localVarRequestOptions.headers = {...localVarHeaderParameter, ...headersFromBaseOptions, ...options.headers};
localVarRequestOptions.data = serializeDataIfNeeded(data, localVarRequestOptions, configuration)

return {
url: toPathString(localVarUrlObj),
options: localVarRequestOptions,
};
},
/**
* Allows the user to set score for a user in an exam.
* @summary Set score for a user in an exam
Expand Down Expand Up @@ -4031,6 +4205,20 @@ export const ExamApiFp = function(configuration?: Configuration) {
const localVarOperationServerBasePath = operationServerMap['ExamApi.getUserOngoingExamsV1']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
* Allows the user to search exams.
* @summary Search exams
* @param {string} authorization Authorization token
* @param {SearchExamData} data Data needed to search exams
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
async searchExamV1(authorization: string, data: SearchExamData, options?: RawAxiosRequestConfig): Promise<(axios?: AxiosInstance, basePath?: string) => AxiosPromise<SearchExamV1200Response>> {
const localVarAxiosArgs = await localVarAxiosParamCreator.searchExamV1(authorization, data, options);
const localVarOperationServerIndex = configuration?.serverIndex ?? 0;
const localVarOperationServerBasePath = operationServerMap['ExamApi.searchExamV1']?.[localVarOperationServerIndex]?.url;
return (axios, basePath) => createRequestFunction(localVarAxiosArgs, globalAxios, BASE_PATH, configuration)(axios, localVarOperationServerBasePath || basePath);
},
/**
* Allows the user to set score for a user in an exam.
* @summary Set score for a user in an exam
Expand Down Expand Up @@ -4143,6 +4331,17 @@ export const ExamApiFactory = function (configuration?: Configuration, basePath?
getUserOngoingExamsV1(authorization: string, targetId?: string, options?: any): AxiosPromise<GetUserOngoingExamsV1200Response> {
return localVarFp.getUserOngoingExamsV1(authorization, targetId, options).then((request) => request(axios, basePath));
},
/**
* Allows the user to search exams.
* @summary Search exams
* @param {string} authorization Authorization token
* @param {SearchExamData} data Data needed to search exams
* @param {*} [options] Override http request option.
* @throws {RequiredError}
*/
searchExamV1(authorization: string, data: SearchExamData, options?: any): AxiosPromise<SearchExamV1200Response> {
return localVarFp.searchExamV1(authorization, data, options).then((request) => request(axios, basePath));
},
/**
* Allows the user to set score for a user in an exam.
* @summary Set score for a user in an exam
Expand Down Expand Up @@ -4268,6 +4467,19 @@ export class ExamApi extends BaseAPI {
return ExamApiFp(this.configuration).getUserOngoingExamsV1(authorization, targetId, options).then((request) => request(this.axios, this.basePath));
}

/**
* Allows the user to search exams.
* @summary Search exams
* @param {string} authorization Authorization token
* @param {SearchExamData} data Data needed to search exams
* @param {*} [options] Override http request option.
* @throws {RequiredError}
* @memberof ExamApi
*/
public searchExamV1(authorization: string, data: SearchExamData, options?: RawAxiosRequestConfig) {
return ExamApiFp(this.configuration).searchExamV1(authorization, data, options).then((request) => request(this.axios, this.basePath));
}

/**
* Allows the user to set score for a user in an exam.
* @summary Set score for a user in an exam
Expand Down
17 changes: 17 additions & 0 deletions src/apiClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,8 @@ import {
EditExamData,
EditExamResult,
GetExamInfoResult,
SearchExamData,
SearchExamResult,
} from './api';
import { canParseAsNumber } from './utils/textUtils';
import { SupportedTranslations } from './translations/translationSwitcher';
Expand Down Expand Up @@ -435,6 +437,21 @@ class ExamSphereAPIClient extends UserApi {
return searchCourseResult;
}

public async searchExam(searchExamData: SearchExamData): Promise<SearchExamResult> {
if (!this.isLoggedIn()) {
throw new Error("Not logged in");
}

let searchExamResult = (await this.examApi.searchExamV1(`Bearer ${this.accessToken}`, searchExamData))?.data.result;
if (!searchExamResult) {
// we shouldn't reach here, because if there is an error somewhere,
// it should have already been thrown by the API client
throw new Error("Failed to search exam");
}

return searchExamResult;
}

public async createNewTopic(data: CreateNewTopicData): Promise<CreateNewTopicResult> {
if (!this.isLoggedIn()) {
throw new Error("Not logged in");
Expand Down
Loading

0 comments on commit 369f1c2

Please sign in to comment.