├── .dockerignore
├── .editorconfig
├── .eslintignore
├── .eslintrc.js
├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug-report.md
│ ├── data-issue-report.md
│ └── feature-request.md
├── auto-label.json
├── pull_request_template.md
└── workflows
│ ├── deploy-bumblebee.yaml
│ ├── deploy-sloths.yaml
│ ├── deploy.yaml
│ ├── nextjs_bundle_analysis.yml.disabled
│ ├── pull_request.yml
│ ├── pull_request_close.yml
│ ├── renovate.yml
│ └── test_report.yml
├── .gitignore
├── .prettierignore
├── .prettierrc
├── CONTRIBUTING.md
├── LICENSE
├── README.md
├── client
├── .dockerignore
├── .env.example
├── Dockerfile
├── Dockerfile.lambda
├── eslint.config.mjs
├── jest.config.mjs
├── lambda
│ ├── app.ts
│ └── event.json
├── next-env.d.ts
├── next.config.mjs
├── next.config.prod.mjs
├── package.json
├── playwright.config.ts
├── public
│ └── static
│ │ ├── empty.txt
│ │ ├── images
│ │ ├── favicon.ico
│ │ ├── im-fine.svg
│ │ ├── job
│ │ │ └── dot.png
│ │ ├── logo-rsschool.svg
│ │ ├── logo-rsschool2.png
│ │ ├── logo-rsschool3.png
│ │ ├── logo_rs.png
│ │ ├── rs-hero.png
│ │ └── united-kingdom.png
│ │ └── svg
│ │ ├── badges
│ │ ├── Congratulations.svg
│ │ ├── Contributor.svg
│ │ ├── Coordinator.svg
│ │ ├── ExpertHelp.svg
│ │ ├── GoodJob.svg
│ │ ├── GreatSpeaker.svg
│ │ ├── HelpingHandSloth.svg
│ │ ├── Hero.svg
│ │ ├── JobOffer.svg
│ │ ├── JuryTeam.svg
│ │ ├── Mentor.svg
│ │ ├── OutstandingWork.svg
│ │ ├── RSActivist.svg
│ │ ├── ThankYou.svg
│ │ ├── Thanks.svg
│ │ └── TopPerformer.svg
│ │ ├── disciplines
│ │ ├── android-archived.svg
│ │ ├── android.svg
│ │ ├── angular-archived.svg
│ │ ├── angular.svg
│ │ ├── ios-archived.svg
│ │ ├── ios.svg
│ │ ├── javascript-archived.svg
│ │ ├── javascript.svg
│ │ ├── machine-learning-archived.svg
│ │ ├── machine-learning.svg
│ │ ├── nodejs-archived.svg
│ │ ├── nodejs-aws-archived.svg
│ │ ├── nodejs-aws.svg
│ │ ├── nodejs.svg
│ │ ├── reactjs-archived.svg
│ │ └── reactjs.svg
│ │ ├── err.svg
│ │ ├── jobs
│ │ ├── logo-footer-github.svg
│ │ ├── logo-footer-rs.svg
│ │ ├── rs-github.svg
│ │ ├── rs-jobs-logo.svg
│ │ ├── rs-logo-big.svg
│ │ └── rs-super-sloth.svg
│ │ ├── logo-epam.svg
│ │ ├── logo-github.svg
│ │ ├── logo-rs.svg
│ │ ├── master-yoda.svg
│ │ ├── sloths
│ │ ├── Expert.svg
│ │ ├── Thanks.svg
│ │ ├── mentor.svg
│ │ └── students.svg
│ │ ├── solidarity-Ukraine.svg
│ │ ├── united-kingdom.svg
│ │ └── wanted-mentors.svg
├── specs
│ └── smoke.spec.ts
├── src
│ ├── __mocks__
│ │ └── axios.js
│ ├── __tests__
│ │ ├── ProfilePage.test.tsx
│ │ └── __snapshots__
│ │ │ └── ProfilePage.test.tsx.snap
│ ├── api
│ │ ├── .gitignore
│ │ ├── .npmignore
│ │ ├── .openapi-generator-ignore
│ │ ├── .openapi-generator
│ │ │ ├── FILES
│ │ │ └── VERSION
│ │ ├── api.ts
│ │ ├── base.ts
│ │ ├── common.ts
│ │ ├── configuration.ts
│ │ ├── git_push.sh
│ │ └── index.ts
│ ├── components
│ │ ├── Analytics.tsx
│ │ ├── CommentModal.tsx
│ │ ├── CopyToClipboardButton.tsx
│ │ ├── CountBadge
│ │ │ ├── CountBadge.tsx
│ │ │ └── index.tsx
│ │ ├── CoursePageLayout.tsx
│ │ ├── Footer
│ │ │ ├── Donation.tsx
│ │ │ ├── Feedback.tsx
│ │ │ ├── FooterLayout.tsx
│ │ │ ├── Help.tsx
│ │ │ ├── Menu.tsx
│ │ │ ├── SocialNetworks.tsx
│ │ │ └── index.tsx
│ │ ├── Forms
│ │ │ ├── CommentInput.tsx
│ │ │ ├── CourseTaskSelect.tsx
│ │ │ ├── GdprCheckbox.tsx
│ │ │ ├── Heroes
│ │ │ │ └── index.tsx
│ │ │ ├── LocationSelect.tsx
│ │ │ ├── MarkdownInput.tsx
│ │ │ ├── ModalForm.tsx
│ │ │ ├── ModalSubmitForm.test.tsx
│ │ │ ├── ModalSubmitForm.tsx
│ │ │ ├── PreparedComment.tsx
│ │ │ ├── ScoreInput.tsx
│ │ │ ├── __tests__
│ │ │ │ ├── CourseTaskSelect.test.tsx
│ │ │ │ └── __snapshots__
│ │ │ │ │ └── CourseTaskSelect.test.tsx.snap
│ │ │ └── index.ts
│ │ ├── GithubAvatar.tsx
│ │ ├── GithubUserLink.tsx
│ │ ├── Header.tsx
│ │ ├── Heroes
│ │ │ ├── HeroesCountBadge.tsx
│ │ │ ├── HeroesRadarTab.tsx
│ │ │ └── HeroesRadarTable.tsx
│ │ ├── Icons
│ │ │ ├── CourseIcon.tsx
│ │ │ ├── DeadlineIcon.tsx
│ │ │ ├── DiscordFilled.tsx
│ │ │ ├── DiscordOutlined.tsx
│ │ │ ├── GitHubLogoIcon.tsx
│ │ │ ├── HealthMask.tsx
│ │ │ ├── LinkedInIcon.tsx
│ │ │ ├── RSLogoIcon.tsx
│ │ │ ├── ScoreIcon.tsx
│ │ │ ├── TelegramIcon.tsx
│ │ │ └── index.tsx
│ │ ├── LoadingScreen.tsx
│ │ ├── MentorOptions.tsx
│ │ ├── MentorSearch.tsx
│ │ ├── PageLayout.tsx
│ │ ├── PersonSelect.tsx
│ │ ├── Profile
│ │ │ ├── AboutCard.tsx
│ │ │ ├── CommonCard.tsx
│ │ │ ├── CommonCardWithSettingsModal.tsx
│ │ │ ├── ContactsCard.tsx
│ │ │ ├── ContactsCardForm.tsx
│ │ │ ├── CoreJsIviewsCard.tsx
│ │ │ ├── CoreJsIviewsModal.tsx
│ │ │ ├── DiscordCard.tsx
│ │ │ ├── EducationCard.tsx
│ │ │ ├── EmailConfirmation.tsx
│ │ │ ├── LanguagesCard.tsx
│ │ │ ├── LegacyScreeningFeedback.tsx
│ │ │ ├── MainCard.tsx
│ │ │ ├── MentorStatsCard.tsx
│ │ │ ├── MentorStatsModal.tsx
│ │ │ ├── ObfuscateConfirmationModal.tsx
│ │ │ ├── PreScreeningIviewCard.tsx
│ │ │ ├── PreScreeningIviewModal.tsx
│ │ │ ├── PrescreeningFeedback.tsx
│ │ │ ├── ProfileSettingsModal.tsx
│ │ │ ├── PublicFeedbackCard.tsx
│ │ │ ├── PublicFeedbackModal.tsx
│ │ │ ├── StudentStatsCard.tsx
│ │ │ ├── StudentStatsModal.tsx
│ │ │ └── __test__
│ │ │ │ ├── AboutCard.test.tsx
│ │ │ │ ├── CommonCard.test.tsx
│ │ │ │ ├── CommonCardWithSettingsModal.test.tsx
│ │ │ │ ├── ContactsCard.test.tsx
│ │ │ │ ├── ContactsCardForm.test.tsx
│ │ │ │ ├── CoreJsIviewsCard.test.tsx
│ │ │ │ ├── CoreJsIviewsModal.test.tsx
│ │ │ │ ├── EducationCard.test.tsx
│ │ │ │ ├── MainCard.test.tsx
│ │ │ │ ├── MentorStatsCard.test.tsx
│ │ │ │ ├── MentorStatsModal.test.tsx
│ │ │ │ ├── PreScreeningIviewCard.test.tsx
│ │ │ │ ├── PreScreeningIviewModal.test.tsx
│ │ │ │ ├── ProfileSettingsModal.test.tsx
│ │ │ │ ├── PublicFeedbackCard.test.tsx
│ │ │ │ ├── PublicFeedbackModal.test.tsx
│ │ │ │ ├── StudentStatsCard.test.tsx
│ │ │ │ ├── StudentStatsModal.test.tsx
│ │ │ │ └── __snapshots__
│ │ │ │ ├── AboutCard.test.tsx.snap
│ │ │ │ ├── CommonCard.test.tsx.snap
│ │ │ │ ├── CommonCardWithSettingsModal.test.tsx.snap
│ │ │ │ ├── ContactsCard.test.tsx.snap
│ │ │ │ ├── ContactsCardForm.test.tsx.snap
│ │ │ │ ├── CoreJsIviewsCard.test.tsx.snap
│ │ │ │ ├── CoreJsIviewsModal.test.tsx.snap
│ │ │ │ ├── EducationCard.test.tsx.snap
│ │ │ │ ├── MainCard.test.tsx.snap
│ │ │ │ ├── MentorStatsCard.test.tsx.snap
│ │ │ │ ├── MentorStatsModal.test.tsx.snap
│ │ │ │ ├── PreScreeningIviewCard.test.tsx.snap
│ │ │ │ ├── PreScreeningIviewModal.test.tsx.snap
│ │ │ │ ├── ProfileSettingsModal.test.tsx.snap
│ │ │ │ ├── PublicFeedbackCard.test.tsx.snap
│ │ │ │ ├── PublicFeedbackModal.test.tsx.snap
│ │ │ │ ├── StudentStatsCard.test.tsx.snap
│ │ │ │ └── StudentStatsModal.test.tsx.snap
│ │ ├── Rating.tsx
│ │ ├── RegistrationPageLayout.tsx
│ │ ├── ScoreCard.tsx
│ │ ├── ScoreSelector.tsx
│ │ ├── SelectLanguages.tsx
│ │ ├── Sider
│ │ │ ├── AdminSider.test.tsx
│ │ │ ├── AdminSider.tsx
│ │ │ └── data
│ │ │ │ └── menuItems.tsx
│ │ ├── SlothImage.tsx
│ │ ├── SolidarityUkraine.tsx
│ │ ├── Student
│ │ │ ├── AssignStudentModal.tsx
│ │ │ ├── DashboardDetails.tsx
│ │ │ └── index.ts
│ │ ├── StudentDiscord.tsx
│ │ ├── StudentMentorModal.tsx
│ │ ├── StudentSearch.tsx
│ │ ├── Table
│ │ │ ├── PersonCell.tsx
│ │ │ ├── columns.tsx
│ │ │ ├── index.ts
│ │ │ ├── renderers.tsx
│ │ │ └── sorters.ts
│ │ ├── TabsWithCounter
│ │ │ └── renderers.tsx
│ │ ├── Timer.tsx
│ │ ├── TooltipedButton.tsx
│ │ ├── UserSearch.tsx
│ │ ├── Warning
│ │ │ └── index.tsx
│ │ ├── WelcomeCard.tsx
│ │ ├── __tests__
│ │ │ └── StudenDiscrod.test.tsx
│ │ ├── common
│ │ │ └── CustomPopconfirm.tsx
│ │ ├── useLoading.tsx
│ │ ├── withGoogleMaps.tsx
│ │ └── withSession.tsx
│ ├── configs
│ │ ├── cdn.ts
│ │ ├── course-icons.ts
│ │ ├── discord-integration.ts
│ │ ├── gcp.ts
│ │ ├── heroes-badges.ts
│ │ ├── registry.ts
│ │ └── timezones.ts
│ ├── data
│ │ ├── english.ts
│ │ ├── eventTypes.ts
│ │ ├── index.ts
│ │ ├── interviews
│ │ │ ├── angular.ts
│ │ │ ├── corejs1.ts
│ │ │ ├── corejs2.ts
│ │ │ ├── index.ts
│ │ │ ├── react.ts
│ │ │ ├── shortTrackJavaScript.ts
│ │ │ ├── shortTrackPerformance.ts
│ │ │ ├── shortTrackScreening.ts
│ │ │ ├── shortTrackTypeScript.ts
│ │ │ ├── technical-screening.tsx
│ │ │ └── types.ts
│ │ ├── skills.ts
│ │ ├── taskTypes.ts
│ │ └── tshirts.ts
│ ├── domain
│ │ ├── course.test.ts
│ │ ├── course.ts
│ │ ├── interview.test.ts
│ │ ├── interview.tsx
│ │ ├── user.test.tsx
│ │ └── user.ts
│ ├── favicon.ico
│ ├── hooks
│ │ ├── index.ts
│ │ └── useModal
│ │ │ ├── useModalForm.test.tsx
│ │ │ └── useModalForm.tsx
│ ├── index.d.ts
│ ├── modules
│ │ ├── AutoTest
│ │ │ ├── components
│ │ │ │ ├── AttemptsAnswers
│ │ │ │ │ └── AttemptsAnswers.tsx
│ │ │ │ ├── AutoTestTaskCard
│ │ │ │ │ └── AutoTestTaskCard.tsx
│ │ │ │ ├── Coding
│ │ │ │ │ ├── Coding.test.tsx
│ │ │ │ │ └── Coding.tsx
│ │ │ │ ├── Exercise
│ │ │ │ │ └── Exercise.tsx
│ │ │ │ ├── JupyterNotebook
│ │ │ │ │ └── JupyterNotebook.tsx
│ │ │ │ ├── Question
│ │ │ │ │ └── Question.tsx
│ │ │ │ ├── SelfEducation
│ │ │ │ │ ├── SelfEducation.test.tsx
│ │ │ │ │ └── SelfEducation.tsx
│ │ │ │ ├── StatusTabs
│ │ │ │ │ ├── StatusTabs.test.tsx
│ │ │ │ │ ├── StatusTabs.tsx
│ │ │ │ │ └── renderers.tsx
│ │ │ │ ├── TaskCard
│ │ │ │ │ ├── TaskCard.test.tsx
│ │ │ │ │ └── TaskCard.tsx
│ │ │ │ ├── TaskCardColumn
│ │ │ │ │ └── TaskCardColumn.tsx
│ │ │ │ ├── TaskDeadlineDate
│ │ │ │ │ ├── TaskDeadlineDate.test.tsx
│ │ │ │ │ └── TaskDeadlineDate.tsx
│ │ │ │ ├── TaskDescription
│ │ │ │ │ └── TaskDescription.tsx
│ │ │ │ ├── VerificationInformation
│ │ │ │ │ ├── VerificationInformation.test.tsx
│ │ │ │ │ └── VerificationInformation.tsx
│ │ │ │ ├── VerificationsTable
│ │ │ │ │ ├── VerificationsTable.test.tsx
│ │ │ │ │ ├── VerificationsTable.tsx
│ │ │ │ │ └── renderers.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── hooks
│ │ │ │ ├── index.ts
│ │ │ │ ├── useAttemptsMessage
│ │ │ │ │ ├── useAttemptsMessage.test.ts
│ │ │ │ │ └── useAttemptsMessage.ts
│ │ │ │ ├── useCourseTaskSubmit
│ │ │ │ │ ├── useCourseTaskSubmit.test.ts
│ │ │ │ │ └── useCourseTaskSubmit.ts
│ │ │ │ ├── useCourseTaskVerifications
│ │ │ │ │ └── useCourseTaskVerifications.ts
│ │ │ │ └── useVerificationsAnswers
│ │ │ │ │ └── useVerificationsAnswers.ts
│ │ │ ├── pages
│ │ │ │ ├── AutoTests
│ │ │ │ │ └── AutoTests.tsx
│ │ │ │ ├── Task
│ │ │ │ │ └── Task.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── types.ts
│ │ │ └── utils
│ │ │ │ └── map.ts
│ │ ├── Contributor
│ │ │ ├── components
│ │ │ │ ├── ContributorModal.tsx
│ │ │ │ └── ContributorsTable.tsx
│ │ │ └── pages
│ │ │ │ └── ContributorPage.tsx
│ │ ├── Course
│ │ │ ├── components
│ │ │ │ ├── CourseNoAccess.tsx
│ │ │ │ └── NoSubmissionAvailable
│ │ │ │ │ └── index.tsx
│ │ │ ├── contexts
│ │ │ │ ├── ActiveCourseContext.tsx
│ │ │ │ ├── SessionContext.test.tsx
│ │ │ │ ├── SessionContext.tsx
│ │ │ │ └── index.ts
│ │ │ └── pages
│ │ │ │ ├── CouseNoAccess
│ │ │ │ └── index.tsx
│ │ │ │ └── Student
│ │ │ │ └── CrossCheckSubmit
│ │ │ │ └── index.tsx
│ │ ├── CourseManagement
│ │ │ └── components
│ │ │ │ ├── CertificateCriteriaModal
│ │ │ │ ├── CertificateCriteriaModal.test.tsx
│ │ │ │ └── CertificateCriteriaModal.tsx
│ │ │ │ ├── CourseEventModal
│ │ │ │ ├── formState.ts
│ │ │ │ └── index.tsx
│ │ │ │ ├── CourseModal
│ │ │ │ └── index.tsx
│ │ │ │ ├── CourseTaskModal
│ │ │ │ └── index.tsx
│ │ │ │ ├── CoursesListModal
│ │ │ │ └── index.tsx
│ │ │ │ ├── ExpelCriteriaModal
│ │ │ │ ├── ExpelCriteriaModal.test.tsx
│ │ │ │ └── ExpelCriteriaModal.tsx
│ │ │ │ ├── SelectCourseTasks
│ │ │ │ ├── SelectCourseTasks.test.tsx
│ │ │ │ └── SelectCourseTasks.tsx
│ │ │ │ └── index.ts
│ │ ├── CourseStatistics
│ │ │ ├── components
│ │ │ │ ├── CountriesChart
│ │ │ │ │ └── CountriesChart.tsx
│ │ │ │ ├── DonutChart
│ │ │ │ │ └── DonutChart.tsx
│ │ │ │ ├── EpamMentorsStatsCard
│ │ │ │ │ ├── EpamMentorsStatsCard.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── LiquidChart
│ │ │ │ │ └── LiquidChart.tsx
│ │ │ │ ├── MentorsCountriesCard
│ │ │ │ │ ├── MentorsCountriesCard.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── StudentsCertificatesCountriesCard
│ │ │ │ │ ├── StudentsCertificatesCountriesCard.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── StudentsCountriesCard
│ │ │ │ │ ├── StudentsCountriesCard.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── StudentsEligibleForCertificationCard
│ │ │ │ │ ├── StudentsEligibleForCertificationCard.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── StudentsStatsCard
│ │ │ │ │ ├── StudentsStatsCard.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── StudentsWithCertificateCard
│ │ │ │ │ ├── StudentsWithCertificateCard.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── StudentsWithMentorsCard
│ │ │ │ │ ├── StudentsWithMentorsCard.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ └── TaskPerformanceCard
│ │ │ │ │ ├── TaskPerformanceCard.tsx
│ │ │ │ │ └── index.tsx
│ │ │ ├── data.ts
│ │ │ ├── hooks
│ │ │ │ ├── index.ts
│ │ │ │ └── useCourseStats
│ │ │ │ │ └── useCourseStats.tsx
│ │ │ ├── index.tsx
│ │ │ └── pages
│ │ │ │ └── CourseStatistics.tsx
│ │ ├── CrossCheck
│ │ │ ├── AddCriteriaForCrossCheck.tsx
│ │ │ ├── CriteriaActions.tsx
│ │ │ ├── CriteriaTypeSelect.tsx
│ │ │ ├── DeleteAllCrossCheckCriteriaButton.tsx
│ │ │ ├── EditableCellForCrossCheck.tsx
│ │ │ ├── EditableCriteriaInput.tsx
│ │ │ ├── EditableTableForCrossCheck.tsx
│ │ │ ├── ExportJSONButton.tsx
│ │ │ ├── UploadCriteriaJSON.tsx
│ │ │ ├── __tests__
│ │ │ │ ├── AddCriteriaForCrossCheck.test.tsx
│ │ │ │ ├── ExportJSONButton.test.tsx
│ │ │ │ ├── UploadCriteriaJSON.test.tsx
│ │ │ │ └── __snapshots__
│ │ │ │ │ └── AddCriteriaForCrossCheck.test.tsx.snap
│ │ │ ├── components
│ │ │ │ ├── CriteriaForm.tsx
│ │ │ │ ├── CrossCheckAssignmentLink.tsx
│ │ │ │ ├── CrossCheckCriteriaForm.tsx
│ │ │ │ ├── CrossCheckHistory.tsx
│ │ │ │ ├── SolutionReview
│ │ │ │ │ ├── Message
│ │ │ │ │ │ ├── Message.test.tsx
│ │ │ │ │ │ ├── Message.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── MessageSendingPanel
│ │ │ │ │ │ ├── MessageSendingPanel.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── SolutionReview.tsx
│ │ │ │ │ ├── UserAvatar
│ │ │ │ │ │ ├── UserAvatar.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── Username
│ │ │ │ │ │ ├── Username.test.tsx
│ │ │ │ │ │ ├── Username.tsx
│ │ │ │ │ │ └── index.ts
│ │ │ │ │ ├── helpers.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── SolutionReviewSettingsPanel
│ │ │ │ │ ├── SolutionReviewSettingsPanel.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── SubmittedStatus.tsx
│ │ │ │ └── criteria
│ │ │ │ │ ├── CrossCheckCriteria.tsx
│ │ │ │ │ ├── CrossCheckCriteriaModal.tsx
│ │ │ │ │ ├── PenaltyCriteria.tsx
│ │ │ │ │ ├── SubtaskCriteria.tsx
│ │ │ │ │ └── TitleCriteria.tsx
│ │ │ ├── constants.ts
│ │ │ ├── hooks
│ │ │ │ ├── index.ts
│ │ │ │ └── useSolutionReviewSettings.ts
│ │ │ ├── index.tsx
│ │ │ └── utils
│ │ │ │ ├── addKeyAndIndex.tsx
│ │ │ │ ├── arrayMoveImmutable.tsx
│ │ │ │ └── getCriteriaStatusColor.ts
│ │ ├── CrossCheckPairs
│ │ │ ├── components
│ │ │ │ ├── BadReview
│ │ │ │ │ ├── BadReviewControllers.tsx
│ │ │ │ │ └── BadReviewTable.tsx
│ │ │ │ └── CrossCheckPairsTable
│ │ │ │ │ └── CrossCheckPairsTable.tsx
│ │ │ ├── data
│ │ │ │ └── getCrossCheckPairsColumns.tsx
│ │ │ └── pages
│ │ │ │ └── CrossCheckPairs
│ │ │ │ ├── CrossCheckPairs.tsx
│ │ │ │ └── index.ts
│ │ ├── Discipline
│ │ │ ├── components
│ │ │ │ ├── DisciplineModal.tsx
│ │ │ │ └── DisciplineTable.tsx
│ │ │ └── pages
│ │ │ │ └── DisciplinePage.tsx
│ │ ├── Feedback
│ │ │ ├── components
│ │ │ │ └── FeedbackForm.tsx
│ │ │ └── data
│ │ │ │ └── softSkills.ts
│ │ ├── Home
│ │ │ ├── components
│ │ │ │ ├── CourseSelector
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── HomeSummary
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── NoCourse
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── RegistryBanner
│ │ │ │ │ └── index.tsx
│ │ │ │ └── SystemAlerts
│ │ │ │ │ └── index.tsx
│ │ │ ├── data
│ │ │ │ ├── links.tsx
│ │ │ │ └── loadHomeData.ts
│ │ │ ├── hooks
│ │ │ │ ├── useActiveCourse.test.tsx
│ │ │ │ ├── useActiveCourse.tsx
│ │ │ │ └── useStudentSummary.tsx
│ │ │ └── pages
│ │ │ │ └── HomePage
│ │ │ │ └── index.tsx
│ │ ├── Interview
│ │ │ └── Student
│ │ │ │ ├── components
│ │ │ │ ├── AlertDescription.tsx
│ │ │ │ ├── ExtraInfo.tsx
│ │ │ │ ├── InterviewCard.tsx
│ │ │ │ ├── InterviewDescription.tsx
│ │ │ │ ├── NoInterviewsAlert.tsx
│ │ │ │ └── StatusLabel.tsx
│ │ │ │ ├── data
│ │ │ │ └── getInterviewCardDetails.tsx
│ │ │ │ └── index.ts
│ │ ├── Interviews
│ │ │ ├── data
│ │ │ │ ├── getInterviewData.ts
│ │ │ │ ├── getStageInterviewData.ts
│ │ │ │ └── index.ts
│ │ │ └── pages
│ │ │ │ ├── InterviewFeedback
│ │ │ │ └── index.tsx
│ │ │ │ └── StageInterviewFeedback
│ │ │ │ ├── CustomQuestion.tsx
│ │ │ │ ├── FormItem.tsx
│ │ │ │ ├── NestedRadio.tsx
│ │ │ │ ├── QuestionCard.tsx
│ │ │ │ ├── QuestionList.tsx
│ │ │ │ ├── QuestionsPicker.tsx
│ │ │ │ ├── StageInterviewFeedback.tsx
│ │ │ │ ├── StepContext.tsx
│ │ │ │ ├── StepForm.tsx
│ │ │ │ ├── Steps.tsx
│ │ │ │ ├── StepsContent.tsx
│ │ │ │ ├── StudentInfo.tsx
│ │ │ │ ├── SubHeader.tsx
│ │ │ │ ├── feedbackTemplateHandler.test.ts
│ │ │ │ ├── feedbackTemplateHandler.ts
│ │ │ │ └── index.ts
│ │ ├── Mentor
│ │ │ ├── components
│ │ │ │ ├── Instructions
│ │ │ │ │ ├── Instructions.tsx
│ │ │ │ │ ├── constants.ts
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── renderers.tsx
│ │ │ │ ├── MentorDashboard
│ │ │ │ │ ├── MentorDashboard.test.tsx
│ │ │ │ │ ├── MentorDashboard.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── Notification
│ │ │ │ │ ├── Notification.test.tsx
│ │ │ │ │ ├── Notification.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ReviewRandomTask
│ │ │ │ │ ├── ReviewRandomTask.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SubmitReviewModal
│ │ │ │ │ ├── SubmitReviewModal.test.tsx
│ │ │ │ │ ├── SubmitReviewModal.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TaskSolutionsTable
│ │ │ │ │ ├── TaskSolutionsTable.test.tsx
│ │ │ │ │ ├── TaskSolutionsTable.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── renderers.tsx
│ │ │ │ ├── TaskStatusTabs
│ │ │ │ │ ├── TaskStatusTabs.test.tsx
│ │ │ │ │ ├── TaskStatusTabs.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── renderers.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── constants.ts
│ │ │ ├── data
│ │ │ │ └── softSkills.ts
│ │ │ ├── hooks
│ │ │ │ ├── useMentorDashboard.tsx
│ │ │ │ └── useMentorStudents.tsx
│ │ │ └── pages
│ │ │ │ ├── InterviewWaitingList
│ │ │ │ └── index.tsx
│ │ │ │ ├── Interviews
│ │ │ │ ├── components
│ │ │ │ │ ├── InterviewCard.tsx
│ │ │ │ │ ├── InterviewDetails.tsx
│ │ │ │ │ ├── InterviewsList.tsx
│ │ │ │ │ ├── InterviewsSummary.tsx
│ │ │ │ │ ├── MentorPreferencesModal.tsx
│ │ │ │ │ ├── RegistrationNotice.test.tsx
│ │ │ │ │ ├── RegistrationNoticeAlert.tsx
│ │ │ │ │ ├── SelectMentorModal.tsx
│ │ │ │ │ ├── StudentInterview.tsx
│ │ │ │ │ └── WaitListAlert.tsx
│ │ │ │ ├── hooks
│ │ │ │ │ └── useAlert.ts
│ │ │ │ └── index.tsx
│ │ │ │ ├── StudentFeedback
│ │ │ │ └── index.tsx
│ │ │ │ └── Students
│ │ │ │ └── index.tsx
│ │ ├── MentorRegistry
│ │ │ ├── components
│ │ │ │ ├── InviteMentorsModal.tsx
│ │ │ │ ├── MentorRegistryDeleteModal.tsx
│ │ │ │ ├── MentorRegistryResendModal.tsx
│ │ │ │ ├── MentorRegistryTable.tsx
│ │ │ │ └── MentorRegistryTableContainer.tsx
│ │ │ ├── constants.ts
│ │ │ └── index.ts
│ │ ├── MentorTasksReview
│ │ │ ├── components
│ │ │ │ ├── AssignReviewerModal
│ │ │ │ │ ├── AssignReviewerModal.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ └── ReviewsTable
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── renderers.tsx
│ │ │ └── pages
│ │ │ │ ├── MentorTasksReview.constants.ts
│ │ │ │ └── MentorTasksReview.tsx
│ │ ├── NotAccess
│ │ │ ├── NotAccess.tsx
│ │ │ └── index.ts
│ │ ├── Notifications
│ │ │ ├── components
│ │ │ │ ├── Consents.tsx
│ │ │ │ ├── NotificationSettingsModal.tsx
│ │ │ │ ├── NotificationSettingsTable.tsx
│ │ │ │ └── NotificationsUserSettingsTable.tsx
│ │ │ ├── pages
│ │ │ │ ├── AdminNotificationsPage
│ │ │ │ │ ├── AdminNotificationsSettingsPage.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ConnectionConfirmedPage.tsx
│ │ │ │ └── UserNotificationsSettingsPage.tsx
│ │ │ └── services
│ │ │ │ └── notifications.ts
│ │ ├── Opportunities
│ │ │ ├── components
│ │ │ │ ├── AvatarCv
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── EditCv
│ │ │ │ │ ├── ContactsForm
│ │ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── GeneralInfoForm
│ │ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── VisibleCoursesForm
│ │ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── form-validation.ts
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── EditViewCv
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ExpirationTooltip
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── Link
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── NameTitle
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── NoConsentView
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── PublicLink
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SidebarSectionHeader
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── StudentStatus
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ └── ViewCv
│ │ │ │ │ ├── AboutSection
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── ActionButtons
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── BaseSection
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── ContactsSection
│ │ │ │ │ ├── ContactsList
│ │ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── CoursesSection
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── DataTextValue
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── FeedbackSection
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── GratitudeSection
│ │ │ │ │ ├── GratitudeList
│ │ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── PersonalSection
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ │ ├── index.test.tsx
│ │ │ │ │ └── index.tsx
│ │ │ ├── constants.ts
│ │ │ ├── data
│ │ │ │ ├── __snapshots__
│ │ │ │ │ └── getPersonalToRender.test.tsx.snap
│ │ │ │ ├── getContactsToRender.test.tsx
│ │ │ │ ├── getContactsToRender.ts
│ │ │ │ ├── getPersonalToRender.test.tsx
│ │ │ │ └── getPersonalToRender.tsx
│ │ │ ├── hooks
│ │ │ │ ├── index.ts
│ │ │ │ ├── useExpiration.test.tsx
│ │ │ │ ├── useExpiration.ts
│ │ │ │ ├── useResumeData.test.tsx
│ │ │ │ ├── useResumeData.tsx
│ │ │ │ ├── useViewData.test.tsx
│ │ │ │ └── useViewData.tsx
│ │ │ ├── models.ts
│ │ │ ├── pages
│ │ │ │ ├── EditPage
│ │ │ │ │ └── index.tsx
│ │ │ │ └── PublicPage
│ │ │ │ │ ├── getServerSideProps.ts
│ │ │ │ │ └── index.tsx
│ │ │ └── transformers
│ │ │ │ ├── index.ts
│ │ │ │ ├── splitDataForForms.test.ts
│ │ │ │ ├── splitDataForForms.ts
│ │ │ │ ├── transformFieldsData.test.ts
│ │ │ │ ├── transformFieldsData.ts
│ │ │ │ ├── transformInitialCvData.test.ts
│ │ │ │ └── transformInitialCvData.ts
│ │ ├── Profile
│ │ │ └── components
│ │ │ │ └── MentorEndorsement
│ │ │ │ ├── MentorEndorsement.tsx
│ │ │ │ └── index.tsx
│ │ ├── Prompts
│ │ │ ├── components
│ │ │ │ ├── PromptModal.tsx
│ │ │ │ └── PromptTable.tsx
│ │ │ └── pages
│ │ │ │ └── PromptPage.tsx
│ │ ├── Registry
│ │ │ ├── components
│ │ │ │ ├── Cards
│ │ │ │ │ ├── AdditionalInfo
│ │ │ │ │ │ ├── AdditionalInfo.test.tsx
│ │ │ │ │ │ └── AdditionalInfo.tsx
│ │ │ │ │ ├── ContactInfo
│ │ │ │ │ │ ├── ContactInfo.test.tsx
│ │ │ │ │ │ └── ContactInfo.tsx
│ │ │ │ │ ├── CourseDetails
│ │ │ │ │ │ ├── CourseDetails.test.tsx
│ │ │ │ │ │ └── CourseDetails.tsx
│ │ │ │ │ ├── Disciplines
│ │ │ │ │ │ ├── Disciplines.test.tsx
│ │ │ │ │ │ └── Disciplines.tsx
│ │ │ │ │ ├── PersonalInfo
│ │ │ │ │ │ ├── PersonalInfo.test.tsx
│ │ │ │ │ │ └── PersonalInfo.tsx
│ │ │ │ │ └── Preferences
│ │ │ │ │ │ ├── Preferences.test.tsx
│ │ │ │ │ │ └── Preferences.tsx
│ │ │ │ ├── CourseLabel
│ │ │ │ │ └── CourseLabel.tsx
│ │ │ │ ├── DataProcessingCheckbox
│ │ │ │ │ ├── DataProcessingCheckbox.test.tsx
│ │ │ │ │ └── DataProcessingCheckbox.tsx
│ │ │ │ ├── Footer
│ │ │ │ │ └── Footer.tsx
│ │ │ │ ├── FormButtons
│ │ │ │ │ ├── FormButtons.test.tsx
│ │ │ │ │ └── FormButtons.tsx
│ │ │ │ ├── FormCard
│ │ │ │ │ └── FormCard.tsx
│ │ │ │ ├── FormSections
│ │ │ │ │ ├── DoneSection
│ │ │ │ │ │ ├── DoneSection.test.tsx
│ │ │ │ │ │ └── DoneSection.tsx
│ │ │ │ │ ├── GeneralSection
│ │ │ │ │ │ ├── GeneralSection.test.tsx
│ │ │ │ │ │ └── GeneralSection.tsx
│ │ │ │ │ └── MentorshipSection
│ │ │ │ │ │ ├── MentorshipSection.test.tsx
│ │ │ │ │ │ └── MentorshipSection.tsx
│ │ │ │ ├── Header
│ │ │ │ │ └── Header.tsx
│ │ │ │ ├── LanguagesMentoring
│ │ │ │ │ ├── LanguagesMentoring.test.tsx
│ │ │ │ │ └── LanguagesMentoring.tsx
│ │ │ │ ├── NoCourses
│ │ │ │ │ └── NoCourses.tsx
│ │ │ │ ├── RegistrationForm
│ │ │ │ │ ├── RegistrationForm.test.tsx
│ │ │ │ │ └── RegistrationForm.tsx
│ │ │ │ └── index.tsx
│ │ │ ├── constants
│ │ │ │ └── index.ts
│ │ │ ├── hooks
│ │ │ │ ├── index.ts
│ │ │ │ ├── useFormLayout
│ │ │ │ │ └── useFormLayout.ts
│ │ │ │ ├── useMentorData
│ │ │ │ │ └── useMentorData.tsx
│ │ │ │ └── useStudentData
│ │ │ │ │ └── useStudentData.tsx
│ │ │ └── pages
│ │ │ │ ├── Mentor
│ │ │ │ └── Mentor.tsx
│ │ │ │ ├── Student
│ │ │ │ └── Student.tsx
│ │ │ │ └── index.ts
│ │ ├── Schedule
│ │ │ ├── components
│ │ │ │ ├── AdditionalActions
│ │ │ │ │ ├── AdditionalActions.test.tsx
│ │ │ │ │ ├── AdditionalActions.tsx
│ │ │ │ │ ├── helpers.ts
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── EventDetails
│ │ │ │ │ ├── EventDetails.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── FilteredTags
│ │ │ │ │ ├── FilteredTags.test.tsx
│ │ │ │ │ ├── FilteredTags.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── MobileItemCard
│ │ │ │ │ ├── MobileItemCard.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── SettingsDrawer
│ │ │ │ │ ├── ChangeTagColors.tsx
│ │ │ │ │ ├── SettingsDrawer.tsx
│ │ │ │ │ ├── SettingsItem.tsx
│ │ │ │ │ ├── ShowTableColumns.tsx
│ │ │ │ │ ├── TimeZone.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── SettingsPanel
│ │ │ │ │ ├── SettingsPanel.test.tsx
│ │ │ │ │ ├── SettingsPanel.tsx
│ │ │ │ │ ├── helpers.ts
│ │ │ │ │ └── index.ts
│ │ │ │ ├── StatusTabs
│ │ │ │ │ ├── StatusTabs.test.tsx
│ │ │ │ │ ├── StatusTabs.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── renderers.tsx
│ │ │ │ └── TableView
│ │ │ │ │ ├── TableView.test.tsx
│ │ │ │ │ ├── TableView.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── renderers.tsx
│ │ │ ├── constants.ts
│ │ │ ├── hooks
│ │ │ │ └── useScheduleSettings.ts
│ │ │ ├── index.ts
│ │ │ ├── pages
│ │ │ │ └── SchedulePage
│ │ │ │ │ └── index.tsx
│ │ │ └── utils.ts
│ │ ├── Score
│ │ │ ├── components
│ │ │ │ ├── ExportCsvButton
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── ScoreTable
│ │ │ │ │ ├── Summary.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ └── SettingsModal
│ │ │ │ │ └── index.tsx
│ │ │ ├── data
│ │ │ │ ├── getColumns.tsx
│ │ │ │ ├── getExportCsvUrl.ts
│ │ │ │ ├── getTaskColumns.tsx
│ │ │ │ └── isExportEnabled.ts
│ │ │ ├── hooks
│ │ │ │ ├── types.ts
│ │ │ │ └── useScorePaging.tsx
│ │ │ └── pages
│ │ │ │ └── ScorePage
│ │ │ │ └── index.tsx
│ │ ├── StudentDashboard
│ │ │ ├── components
│ │ │ │ ├── AvailableReviewCard
│ │ │ │ │ ├── AvailableReviewCard.test.tsx
│ │ │ │ │ ├── AvailableReviewCard.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── CommonDashboardCard.tsx
│ │ │ │ ├── MainStatsCard.tsx
│ │ │ │ ├── MentorCard
│ │ │ │ │ ├── MentorCard.test.tsx
│ │ │ │ │ ├── MentorCard.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── MentorInfo
│ │ │ │ │ ├── MentorInfo.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── NextEventCard
│ │ │ │ │ ├── NextEventCard.test.tsx
│ │ │ │ │ ├── NextEventCard.tsx
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── renderers.tsx
│ │ │ │ ├── RepositoryCard.tsx
│ │ │ │ ├── SubmitTaskSolution
│ │ │ │ │ ├── SubmitTaskSolution.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ ├── TasksChart.tsx
│ │ │ │ ├── TasksStatsCard.tsx
│ │ │ │ ├── TasksStatsModal.tsx
│ │ │ │ └── index.ts
│ │ │ ├── hooks
│ │ │ │ ├── useDashboardData.ts
│ │ │ │ ├── useSubmitTaskSolution.test.ts
│ │ │ │ └── useSubmitTaskSolution.ts
│ │ │ └── index.ts
│ │ ├── Students
│ │ │ ├── Pages
│ │ │ │ └── Students.tsx
│ │ │ └── components
│ │ │ │ ├── CourseItem
│ │ │ │ └── index.tsx
│ │ │ │ ├── StudentInfo
│ │ │ │ └── index.tsx
│ │ │ │ └── StudentsTable
│ │ │ │ ├── index.tsx
│ │ │ │ └── renderers.tsx
│ │ ├── Tasks
│ │ │ ├── components
│ │ │ │ ├── CrossCheckTaskCriteriaPanel
│ │ │ │ │ ├── CrossCheckTaskCriteriaPanel.test.tsx
│ │ │ │ │ └── CrossCheckTaskCriteriaPanel.tsx
│ │ │ │ ├── GitHubPanel
│ │ │ │ │ ├── GitHubPanel.test.tsx
│ │ │ │ │ └── GitHubPanel.tsx
│ │ │ │ ├── JsonAttributesPanel
│ │ │ │ │ ├── JsonAttributesPanel.test.tsx
│ │ │ │ │ └── JsonAttributesPanel.tsx
│ │ │ │ ├── TaskModal
│ │ │ │ │ ├── TaskModal.test.tsx
│ │ │ │ │ └── TaskModal.tsx
│ │ │ │ ├── TaskSettings
│ │ │ │ │ ├── TaskSettings.test.tsx
│ │ │ │ │ └── TaskSettings.tsx
│ │ │ │ ├── TasksTable
│ │ │ │ │ ├── TasksTable.test.tsx
│ │ │ │ │ └── TasksTable.tsx
│ │ │ │ └── index.ts
│ │ │ ├── constants.ts
│ │ │ ├── pages
│ │ │ │ ├── TasksPage
│ │ │ │ │ └── TasksPage.tsx
│ │ │ │ └── index.ts
│ │ │ ├── types.ts
│ │ │ └── utils
│ │ │ │ └── test-utils.ts
│ │ ├── TeamDistribution
│ │ │ ├── components
│ │ │ │ ├── SubmitScoreModal
│ │ │ │ │ ├── SubmitScoreModal.tsx
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── TeamDistributionCard
│ │ │ │ │ ├── Actions.test.tsx
│ │ │ │ │ ├── Actions.tsx
│ │ │ │ │ ├── CardTitle.test.tsx
│ │ │ │ │ ├── CardTitle.tsx
│ │ │ │ │ ├── DistributionPeriod.tsx
│ │ │ │ │ ├── TeamDistributionCard.test.tsx
│ │ │ │ │ ├── TeamDistributionCard.tsx
│ │ │ │ │ ├── index.ts
│ │ │ │ │ └── renderers.tsx
│ │ │ │ ├── TeamDistributionModal
│ │ │ │ │ ├── TeamDistributionModal.tsx
│ │ │ │ │ └── index.ts
│ │ │ │ └── WelcomeCard
│ │ │ │ │ ├── WelcomeCard.test.tsx
│ │ │ │ │ ├── WelcomeCard.tsx
│ │ │ │ │ └── index.ts
│ │ │ ├── hooks
│ │ │ │ ├── useSubmitTeamScore.test.tsx
│ │ │ │ └── useSubmitTeamScore.tsx
│ │ │ └── pages
│ │ │ │ └── TeamDistributions
│ │ │ │ ├── TeamDistributions.tsx
│ │ │ │ └── index.tsx
│ │ └── Teams
│ │ │ ├── Pages
│ │ │ └── Teams.tsx
│ │ │ ├── components
│ │ │ ├── JoinTeamModal
│ │ │ │ └── JoinTeamModal.tsx
│ │ │ ├── MyTeamSection
│ │ │ │ └── MyTeamSection.tsx
│ │ │ ├── StudentsTable
│ │ │ │ ├── StudentsTable.tsx
│ │ │ │ └── renderers.tsx
│ │ │ ├── StudentsWithoutTeamSection
│ │ │ │ └── StudentsWithoutTeamSection.tsx
│ │ │ ├── TeamModal
│ │ │ │ ├── TeamModal.test.tsx
│ │ │ │ └── TeamModal.tsx
│ │ │ ├── TeamsHeader
│ │ │ │ ├── ActionCard.tsx
│ │ │ │ └── TeamsHeader.tsx
│ │ │ ├── TeamsSection
│ │ │ │ ├── TeamsSection.tsx
│ │ │ │ └── renderers.tsx
│ │ │ └── index.ts
│ │ │ ├── constants.ts
│ │ │ ├── hooks
│ │ │ ├── index.ts
│ │ │ └── useDistribution
│ │ │ │ ├── useDistribution.test.ts
│ │ │ │ └── useDistribution.ts
│ │ │ ├── index.tsx
│ │ │ └── utils
│ │ │ └── showConfirmationModals.tsx
│ ├── pages
│ │ ├── 404.tsx
│ │ ├── _app.tsx
│ │ ├── _document.tsx
│ │ ├── admin
│ │ │ ├── auto-test-task
│ │ │ │ └── [taskId].tsx
│ │ │ ├── auto-test.tsx
│ │ │ ├── contributors.tsx
│ │ │ ├── courses.tsx
│ │ │ ├── disciplines.tsx
│ │ │ ├── discord-server.tsx
│ │ │ ├── events.tsx
│ │ │ ├── mentor-registry.tsx
│ │ │ ├── notifications.tsx
│ │ │ ├── prompts.tsx
│ │ │ ├── registrations.tsx
│ │ │ ├── students.tsx
│ │ │ ├── tasks.tsx
│ │ │ ├── user-group.tsx
│ │ │ └── users.tsx
│ │ ├── applicants
│ │ │ └── index.tsx
│ │ ├── course
│ │ │ ├── 403.tsx
│ │ │ ├── admin
│ │ │ │ ├── certified-students.tsx
│ │ │ │ ├── cross-check-table.tsx
│ │ │ │ ├── events.tsx
│ │ │ │ ├── interviews.tsx
│ │ │ │ ├── mentor-tasks-review.tsx
│ │ │ │ ├── mentors.tsx
│ │ │ │ ├── stage-interviews.tsx
│ │ │ │ ├── students.tsx
│ │ │ │ ├── tasks.tsx
│ │ │ │ └── users.tsx
│ │ │ ├── interview
│ │ │ │ └── [type]
│ │ │ │ │ └── feedback.tsx
│ │ │ ├── mentor
│ │ │ │ ├── auto-confirm.tsx
│ │ │ │ ├── confirm.tsx
│ │ │ │ ├── dashboard.tsx
│ │ │ │ ├── expel-student.tsx
│ │ │ │ ├── feedback
│ │ │ │ │ └── index.tsx
│ │ │ │ ├── interview-technical-screening.tsx
│ │ │ │ ├── interview-wait-list.tsx
│ │ │ │ ├── interviews.tsx
│ │ │ │ └── students.tsx
│ │ │ ├── schedule.tsx
│ │ │ ├── score.tsx
│ │ │ ├── stats.tsx
│ │ │ ├── student
│ │ │ │ ├── auto-test
│ │ │ │ │ ├── index.tsx
│ │ │ │ │ └── task.tsx
│ │ │ │ ├── cross-check-review.tsx
│ │ │ │ ├── cross-check-submit.tsx
│ │ │ │ ├── dashboard.tsx
│ │ │ │ └── interviews.tsx
│ │ │ ├── submit-scores.tsx
│ │ │ ├── team-distributions.tsx
│ │ │ └── teams.tsx
│ │ ├── cv
│ │ │ ├── [uuid].tsx
│ │ │ └── edit.tsx
│ │ ├── gratitude.tsx
│ │ ├── heroes.tsx
│ │ ├── index.tsx
│ │ ├── login
│ │ │ └── index.tsx
│ │ ├── profile
│ │ │ ├── connection-confirmed.tsx
│ │ │ ├── index.tsx
│ │ │ └── notifications.tsx
│ │ └── registry
│ │ │ ├── epamlearningjs.tsx
│ │ │ ├── mentor.tsx
│ │ │ └── student.tsx
│ ├── reset.d.ts
│ ├── services
│ │ ├── cdn.ts
│ │ ├── check.ts
│ │ ├── course.ts
│ │ ├── courses.ts
│ │ ├── features.tsx
│ │ ├── files.ts
│ │ ├── formatter.ts
│ │ ├── gratitude.ts
│ │ ├── mentorRegistry.ts
│ │ ├── models.ts
│ │ ├── reference-data
│ │ │ └── stageInterview.ts
│ │ ├── routes.ts
│ │ ├── user.ts
│ │ ├── validators.test.ts
│ │ └── validators.ts
│ ├── setupJest.ts
│ ├── styles
│ │ └── main.css
│ └── utils
│ │ ├── axios.ts
│ │ ├── onlyDefined.ts
│ │ ├── optionalQueryString.ts
│ │ ├── profilePageUtils.ts
│ │ ├── queryParams-utils.test.ts
│ │ ├── queryParams-utils.ts
│ │ ├── text-utils.test.ts
│ │ ├── text-utils.ts
│ │ └── useWindowDimensions.ts
└── tsconfig.json
├── common
├── enums
│ └── mentor
│ │ └── index.ts
├── interfaces
│ └── gratitude
│ │ └── index.ts
├── models
│ ├── index.ts
│ ├── interview.ts
│ ├── profile.ts
│ ├── stage-interview-feedback.ts
│ └── user.ts
└── types
│ └── pagination
│ └── index.ts
├── docker-compose.yml
├── docs
├── .nojekyll
├── CNAME
├── README.md
├── _sidebar.md
├── code-of-conduct.md
├── index.html
└── platform
│ ├── about.md
│ ├── adding-tests.md
│ ├── choose-kata-languages.md
│ ├── cross-check-flow.md
│ ├── cross-check-scheduling.md
│ ├── cv.md
│ ├── img
│ ├── adding-tests-1.png
│ ├── adding-tests-2.png
│ ├── adding-tests-3.png
│ ├── adding-tests-4.png
│ ├── adding-tests-5.png
│ ├── adding-tests-6.png
│ ├── adding-tests-7.png
│ ├── adding-tests-8.png
│ ├── autotest-details.jpg
│ ├── choose-kata-languages
│ │ ├── task-json.JPG
│ │ └── task-settings.JPG
│ ├── cross-check-scheduling
│ │ └── course-task-modal.JPG
│ ├── cv
│ │ ├── applicants-page-link.JPG
│ │ ├── applicants-table.JPG
│ │ ├── cv-form-filled-1.JPG
│ │ ├── cv-form-filled.JPG
│ │ ├── cv-view-filled.JPG
│ │ ├── cv-view-print.JPG
│ │ ├── edit-cv-buttons.JPG
│ │ ├── employer-page.JPG
│ │ ├── header-dropdown.JPG
│ │ ├── no-consent-modal.JPG
│ │ ├── no-consent.JPG
│ │ ├── view-control-buttons.JPG
│ │ └── view-delete-cv.JPG
│ ├── no-access.png
│ ├── schedule-1.png
│ ├── schedule-10.png
│ ├── schedule-2.png
│ ├── schedule-3.png
│ ├── schedule-4.png
│ ├── schedule-5.png
│ ├── schedule-6.png
│ ├── schedule-7.png
│ ├── schedule-8.png
│ ├── schedule-9.png
│ └── tasks-1.jpg
│ ├── notifications.md
│ ├── pull-request-review-process.md
│ ├── shedule.md
│ ├── tasks.md
│ └── typical-problems.md
├── eslint.config.mjs
├── nestjs
├── .dockerignore
├── .env.example
├── .prettierrc
├── Dockerfile
├── Dockerfile.lambda
├── README.md
├── eslint.config.mjs
├── jest.config.mjs
├── lambda
│ └── app.js
├── nest-cli.json
├── openapitools.json
├── package.json
├── src
│ ├── activity
│ │ ├── activity.controller.ts
│ │ ├── activity.module.ts
│ │ └── dto
│ │ │ ├── activity.dto.ts
│ │ │ ├── create-activity-webhook.dto.ts
│ │ │ └── create-activity.dto.ts
│ ├── alerts
│ │ ├── alerts.controller.ts
│ │ ├── alerts.module.ts
│ │ ├── alerts.service.ts
│ │ └── dto
│ │ │ ├── alert.dto.ts
│ │ │ ├── create-alert.dto.ts
│ │ │ ├── index.ts
│ │ │ └── update-alert.dto.ts
│ ├── app.module.ts
│ ├── auth
│ │ ├── auth-user.model.spec.ts
│ │ ├── auth-user.model.ts
│ │ ├── auth.controller.spec.ts
│ │ ├── auth.controller.ts
│ │ ├── auth.module.ts
│ │ ├── auth.service.spec.ts
│ │ ├── auth.service.ts
│ │ ├── constants.ts
│ │ ├── course.guard.ts
│ │ ├── default.guard.ts
│ │ ├── dto
│ │ │ └── auth-connection.dto.ts
│ │ ├── index.ts
│ │ ├── role.decorator.ts
│ │ ├── role.guard.ts
│ │ └── strategies
│ │ │ ├── basic.strategy.ts
│ │ │ ├── dev.strategy.ts
│ │ │ ├── github.strategy.ts
│ │ │ └── jwt.strategy.ts
│ ├── auto-test
│ │ ├── auto-test.controller.ts
│ │ ├── auto-test.module.ts
│ │ ├── auto-test.service.ts
│ │ └── dto
│ │ │ ├── auto-test-task.dto.ts
│ │ │ ├── basic-auto-test-task.dto.ts
│ │ │ └── task-solution.dto.ts
│ ├── certificates
│ │ ├── certificates.controller.ts
│ │ ├── certificates.module.ts
│ │ ├── certificates.service.ts
│ │ └── dto
│ │ │ ├── certificate-metadata.dto.ts
│ │ │ └── save-certificate-dto.ts
│ ├── cloud-api
│ │ ├── cloud-api.module.ts
│ │ └── cloud-api.service.ts
│ ├── config
│ │ ├── config.module.ts
│ │ ├── config.service.ts
│ │ └── index.ts
│ ├── constants.ts
│ ├── contributors
│ │ ├── contributors.controller.ts
│ │ ├── contributors.module.ts
│ │ ├── contributors.service.ts
│ │ ├── dto
│ │ │ ├── contributor.dto.ts
│ │ │ ├── create-contributor.dto.ts
│ │ │ ├── index.ts
│ │ │ └── update-contributor.dto.ts
│ │ └── index.ts
│ ├── core
│ │ ├── core.module.ts
│ │ ├── decorators
│ │ │ ├── index.ts
│ │ │ └── student-id.decorator.ts
│ │ ├── dto
│ │ │ ├── id-name.dto.ts
│ │ │ ├── index.ts
│ │ │ ├── pagination.dto.ts
│ │ │ └── person.dto.ts
│ │ ├── filters
│ │ │ ├── entity-not-found.filter.ts
│ │ │ ├── index.ts
│ │ │ └── sentry.filter.ts
│ │ ├── jwt
│ │ │ └── jwt.service.ts
│ │ ├── middlewares
│ │ │ ├── index.ts
│ │ │ ├── logger.middleware.ts
│ │ │ └── no-cache.middleware.ts
│ │ ├── paginate
│ │ │ ├── dto
│ │ │ │ └── Paginate.dto.ts
│ │ │ ├── index.ts
│ │ │ └── test.ts
│ │ ├── pino.ts
│ │ ├── subscribers
│ │ │ ├── base-subscriber.ts
│ │ │ ├── course-event.subscriber.ts
│ │ │ └── course-task.subscriber.ts
│ │ ├── templates
│ │ │ └── index.ts
│ │ └── validation
│ │ │ ├── index.ts
│ │ │ ├── validation.exception.ts
│ │ │ └── validation.filter.ts
│ ├── courses
│ │ ├── course-access.service.ts
│ │ ├── course-events
│ │ │ ├── course-events.controller.ts
│ │ │ ├── course-events.service.ts
│ │ │ ├── dto
│ │ │ │ ├── course-event.dto.ts
│ │ │ │ ├── create-course-event.dto.ts
│ │ │ │ └── update-course-event.dto.ts
│ │ │ └── index.ts
│ │ ├── course-mentors
│ │ │ ├── course-mentors.controller.ts
│ │ │ ├── course-mentors.service.ts
│ │ │ ├── dto
│ │ │ │ ├── mentor-details.dto.ts
│ │ │ │ └── search-mentor.dto.ts
│ │ │ └── index.ts
│ │ ├── course-schedule
│ │ │ ├── course-icalendar.controller.ts
│ │ │ ├── course-icalendar.service.ts
│ │ │ ├── course-schedule.controller.ts
│ │ │ ├── course-schedule.service.spec.ts
│ │ │ ├── course-schedule.service.ts
│ │ │ ├── dto
│ │ │ │ ├── course-copy-from.dto.ts
│ │ │ │ ├── course-schedule-hash.dto.ts
│ │ │ │ ├── course-schedule-item.dto.ts
│ │ │ │ └── index.ts
│ │ │ └── index.ts
│ │ ├── course-students
│ │ │ ├── course-students.controller.ts
│ │ │ ├── course-students.service.ts
│ │ │ └── dto
│ │ │ │ ├── mentor-student-summary.dto.ts
│ │ │ │ ├── result.dto.ts
│ │ │ │ └── student-summary.dto.ts
│ │ ├── course-tasks
│ │ │ ├── course-tasks.controller.ts
│ │ │ ├── course-tasks.service.ts
│ │ │ ├── dto
│ │ │ │ ├── course-task-detailed.dto.ts
│ │ │ │ ├── course-task.dto.ts
│ │ │ │ ├── create-course-task.dto.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── update-course-task.dto.ts
│ │ │ └── index.ts
│ │ ├── course-users
│ │ │ ├── course-users.controller.spec.ts
│ │ │ ├── course-users.controller.ts
│ │ │ ├── course-users.service.spec.ts
│ │ │ ├── course-users.service.ts
│ │ │ ├── dto
│ │ │ │ ├── course-roles.dto.ts
│ │ │ │ ├── course-user.dto.ts
│ │ │ │ └── update-user.dto.ts
│ │ │ └── types.ts
│ │ ├── courses.controller.ts
│ │ ├── courses.module.ts
│ │ ├── courses.service.ts
│ │ ├── cross-checks
│ │ │ ├── course-cross-checks.controller.ts
│ │ │ ├── course-cross-checks.service.spec.ts
│ │ │ ├── course-cross-checks.service.ts
│ │ │ ├── cross-check-feedback.guard.ts
│ │ │ ├── dto
│ │ │ │ ├── available-review-stats.dto.ts
│ │ │ │ ├── check-tasks-pairs.dto.ts
│ │ │ │ ├── cross-check-criteria-data.dto.ts
│ │ │ │ ├── cross-check-feedback.dto.ts
│ │ │ │ └── index.ts
│ │ │ └── index.ts
│ │ ├── dto
│ │ │ ├── course.dto.ts
│ │ │ ├── create-course.dto.ts
│ │ │ ├── export-course.dto.ts
│ │ │ ├── index.ts
│ │ │ ├── leave-course.dto.ts
│ │ │ ├── update-course.dto.ts
│ │ │ └── used-course.dto.ts
│ │ ├── index.ts
│ │ ├── interviews
│ │ │ ├── dto
│ │ │ │ ├── available-student.dto.ts
│ │ │ │ ├── get-interview-feedback.dto.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── interview-pair.dto.ts
│ │ │ │ ├── interview.dto.ts
│ │ │ │ ├── put-interview-feedback.dto.ts
│ │ │ │ └── registration-interview.dto.ts
│ │ │ ├── index.ts
│ │ │ ├── interviewFeedback.service.ts
│ │ │ ├── interviews.controller.ts
│ │ │ └── interviews.service.ts
│ │ ├── mentor-reviews
│ │ │ ├── dto
│ │ │ │ ├── index.ts
│ │ │ │ ├── mentor-review-assign.dto.ts
│ │ │ │ ├── mentor-reviews-query.dto.ts
│ │ │ │ └── mentor-reviews.dto.ts
│ │ │ ├── index.ts
│ │ │ ├── mentor-reviews.controller.ts
│ │ │ └── mentor-reviews.service.ts
│ │ ├── mentors
│ │ │ ├── dto
│ │ │ │ ├── index.ts
│ │ │ │ ├── mentor-dashboard.dto.ts
│ │ │ │ ├── mentor-options.dto.ts
│ │ │ │ └── mentor-student.dto.ts
│ │ │ ├── index.ts
│ │ │ ├── mentors.controller.ts
│ │ │ └── mentors.service.ts
│ │ ├── score
│ │ │ ├── dto
│ │ │ │ ├── score-query.dto.ts
│ │ │ │ └── score.dto.ts
│ │ │ ├── index.ts
│ │ │ ├── score.controller.ts
│ │ │ ├── score.service.ts
│ │ │ └── write-score.service.ts
│ │ ├── stats
│ │ │ ├── course-stats.controller.ts
│ │ │ ├── course-stats.service.ts
│ │ │ ├── dto
│ │ │ │ ├── countries-stats.dto.ts
│ │ │ │ ├── course-mentors-stats.dto.ts
│ │ │ │ ├── course-stats.dto.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── task-performance-stats.dto.ts
│ │ │ └── index.ts
│ │ ├── students
│ │ │ ├── dto
│ │ │ │ ├── index.ts
│ │ │ │ ├── student.dto.ts
│ │ │ │ ├── user-students-query.dto.ts
│ │ │ │ └── user-students.dto.ts
│ │ │ ├── feedbacks
│ │ │ │ ├── dto
│ │ │ │ │ ├── create-student-feedback.dto.ts
│ │ │ │ │ ├── index.ts
│ │ │ │ │ ├── student-feedback.dto.ts
│ │ │ │ │ └── update-student-feedback.dto.ts
│ │ │ │ ├── feedbacks.controller.ts
│ │ │ │ ├── feedbacks.service.ts
│ │ │ │ └── index.ts
│ │ │ ├── index.ts
│ │ │ ├── students.controller.ts
│ │ │ └── students.service.ts
│ │ ├── task-solutions
│ │ │ ├── dto
│ │ │ │ ├── create-task-solution.dto.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── task-solution.dto.ts
│ │ │ ├── index.ts
│ │ │ ├── task-solutions.controller.ts
│ │ │ └── task-solutions.service.ts
│ │ ├── task-verifications
│ │ │ ├── dto
│ │ │ │ ├── create-task-verification.dto.ts
│ │ │ │ ├── index.ts
│ │ │ │ ├── self-education.dto.ts
│ │ │ │ └── task-verifications-attempts.dto.ts
│ │ │ ├── self-education.service.test.ts
│ │ │ ├── self-education.service.ts
│ │ │ ├── task-verifications.controller.ts
│ │ │ └── task-verifications.service.ts
│ │ ├── tasks
│ │ │ ├── dto
│ │ │ │ └── check-tasks-deadline.ts
│ │ │ ├── tasks.controller.ts
│ │ │ └── tasks.service.ts
│ │ └── team-distribution
│ │ │ ├── distribute-students.service.ts
│ │ │ ├── dto
│ │ │ ├── create-team-distribution.dto.ts
│ │ │ ├── create-team.dto.ts
│ │ │ ├── index.ts
│ │ │ ├── join-team.dto.ts
│ │ │ ├── team-distribution-student.dto.ts
│ │ │ ├── team-distribution.dto.ts
│ │ │ ├── team.dto.ts
│ │ │ ├── update-team-distribution.dto.ts
│ │ │ └── update-team-dto.ts
│ │ │ ├── registered-student-guard.ts
│ │ │ ├── team-distribution-student.service.ts
│ │ │ ├── team-distribution.controller.ts
│ │ │ ├── team-distribution.service.ts
│ │ │ ├── team-lead-or-manager.guard.ts
│ │ │ ├── team.controller.ts
│ │ │ └── team.service.ts
│ ├── cross-check
│ │ ├── cross-check.module.ts
│ │ ├── cross-check.service.spec.ts
│ │ ├── cross-check.service.ts
│ │ └── tasks-filtering.ts
│ ├── disciplines
│ │ ├── disciplines.controller.test.ts
│ │ ├── disciplines.controller.ts
│ │ ├── disciplines.module.ts
│ │ ├── disciplines.service.test.ts
│ │ ├── disciplines.service.ts
│ │ ├── dto
│ │ │ ├── create-discipline.dto.ts
│ │ │ ├── discipline.dto.ts
│ │ │ ├── index.ts
│ │ │ └── update-discipline.dto.ts
│ │ └── index.ts
│ ├── discord-servers
│ │ ├── discord-servers.controller.ts
│ │ ├── discord-servers.module.ts
│ │ ├── discord-servers.service.ts
│ │ └── dto
│ │ │ ├── create-discord-server.dto.ts
│ │ │ ├── discord-server.dto.ts
│ │ │ ├── index.ts
│ │ │ └── update-discord-server.dto.ts
│ ├── events
│ │ ├── dto
│ │ │ ├── create-event.dto.ts
│ │ │ ├── event.dto.ts
│ │ │ ├── index.ts
│ │ │ └── update-event.dto.ts
│ │ ├── events.controller.ts
│ │ ├── events.module.ts
│ │ └── events.service.ts
│ ├── gratitudes
│ │ ├── discord.service.ts
│ │ ├── dto
│ │ │ ├── badge.dto.ts
│ │ │ ├── country.dto.ts
│ │ │ ├── create-gratitude.dto.ts
│ │ │ ├── gratitude.dto.ts
│ │ │ ├── hero-radar.dto.ts
│ │ │ ├── heroes-radar-badge.dto.ts
│ │ │ ├── heroes-radar-query.dto.ts
│ │ │ ├── heroes-radar.dto.ts
│ │ │ └── index.ts
│ │ ├── gratitudes.controller.ts
│ │ ├── gratitudes.module.ts
│ │ ├── gratitudes.service.ts
│ │ └── index.ts
│ ├── listeners
│ │ ├── course.listener.ts
│ │ ├── index.ts
│ │ └── listeners.module.ts
│ ├── main.lambda.ts
│ ├── main.ts
│ ├── migrations.ts
│ ├── notifications
│ │ ├── dto
│ │ │ ├── notification.dto.ts
│ │ │ └── update-notification.dto.ts
│ │ ├── email-template.ts
│ │ ├── notifications.controller.ts
│ │ ├── notifications.module.ts
│ │ └── notifications.service.ts
│ ├── openapi-spec.ts
│ ├── opportunities
│ │ ├── dto
│ │ │ ├── applicant-resume.dto.ts
│ │ │ ├── consent.dto.ts
│ │ │ ├── form-data.dto.ts
│ │ │ ├── give-consent-dto.ts
│ │ │ ├── resume.dto.ts
│ │ │ ├── status.dto.ts
│ │ │ └── visibility.dto.ts
│ │ ├── opportunities.controller.ts
│ │ ├── opportunities.module.ts
│ │ └── opportunities.service.ts
│ ├── ormconfig.ts
│ ├── profile
│ │ ├── dto
│ │ │ ├── endorsement.dto.ts
│ │ │ ├── index.ts
│ │ │ ├── personal-profile.dto.ts
│ │ │ ├── profile-course.dto.ts
│ │ │ ├── profile.dto.ts
│ │ │ ├── update-profile.dto.ts
│ │ │ └── update-user.dto.ts
│ │ ├── endorsement.service.ts
│ │ ├── index.ts
│ │ ├── profile.controller.ts
│ │ ├── profile.module.ts
│ │ └── profile.service.ts
│ ├── prompts
│ │ ├── dto
│ │ │ ├── create-prompt.dto.ts
│ │ │ ├── index.ts
│ │ │ ├── prompt.dto.ts
│ │ │ └── update-prompt.dto.ts
│ │ ├── prompts.controller.ts
│ │ ├── prompts.module.ts
│ │ └── prompts.service.ts
│ ├── registry
│ │ ├── constants.ts
│ │ ├── dto
│ │ │ ├── approve-mentor.dto.ts
│ │ │ ├── comment-mentor-registry.dto.ts
│ │ │ ├── invite-mentors.dto.ts
│ │ │ └── mentor-registry.dto.ts
│ │ ├── registry.controller.ts
│ │ ├── registry.module.ts
│ │ └── registry.service.ts
│ ├── reset.d.ts
│ ├── schedule
│ │ ├── dto
│ │ │ └── check-schedule-changes.ts
│ │ ├── schedule.controller.ts
│ │ ├── schedule.module.ts
│ │ └── schedule.service.ts
│ ├── session
│ │ ├── dto
│ │ │ └── auth-user.dto.ts
│ │ ├── session.controller.ts
│ │ └── session.module.ts
│ ├── setup.ts
│ ├── spec.json
│ ├── tasks
│ │ ├── dto
│ │ │ ├── create-task.dto.ts
│ │ │ ├── index.ts
│ │ │ ├── task.dto.ts
│ │ │ └── update-task.dto.ts
│ │ ├── tasks-criteria
│ │ │ ├── dto
│ │ │ │ ├── criteria.dto.ts
│ │ │ │ └── task-criteria.dto.ts
│ │ │ ├── index.ts
│ │ │ ├── tasks-criteria.controller.ts
│ │ │ └── tasks-criteria.service.ts
│ │ ├── tasks.controller.ts
│ │ ├── tasks.module.ts
│ │ └── tasks.service.ts
│ ├── user-groups
│ │ ├── dto
│ │ │ ├── create-user-group.dto.ts
│ │ │ ├── index.ts
│ │ │ ├── update-user-group.dto.ts
│ │ │ └── user-group.dto.ts
│ │ ├── index.ts
│ │ ├── user-groups.controller.ts
│ │ ├── user-groups.module.ts
│ │ └── user-groups.service.ts
│ ├── users-notifications
│ │ ├── dto
│ │ │ ├── notification-connection-exists.dto.ts
│ │ │ ├── notification-connection.dto.ts
│ │ │ ├── notification-user-connections.dto.ts
│ │ │ ├── notification-user-settings.dto.ts
│ │ │ ├── send-user-notification.dto.ts
│ │ │ ├── update-notification-user-settings.dto.ts
│ │ │ └── upsert-notification-connection.dto.ts
│ │ ├── index.ts
│ │ ├── users-notifications.module.ts
│ │ ├── users.notifications.controller.ts
│ │ └── users.notifications.service.ts
│ └── users
│ │ ├── dto
│ │ ├── index.ts
│ │ └── user-search.dto.ts
│ │ ├── index.ts
│ │ ├── users.controller.ts
│ │ ├── users.module.ts
│ │ └── users.service.ts
├── test
│ ├── app.e2e-spec.ts
│ └── jest-e2e.json
├── tsconfig.build.json
└── tsconfig.json
├── package-lock.json
├── package.json
├── renovate.json
├── server
├── .dockerignore
├── .env.example
├── Dockerfile
├── Dockerfile.lambda
├── eslint.config.mjs
├── jest.config.mjs
├── lambda
│ └── app.js
├── package.json
├── public
│ └── swagger.yml
├── src
│ ├── app.ts
│ ├── config.ts
│ ├── dataSource.ts
│ ├── dataSourceOptions.ts
│ ├── index.ts
│ ├── logger.ts
│ ├── migrations
│ │ ├── 1630340371992-UserMigration.ts
│ │ ├── 1630341383942-TaskResult.ts
│ │ ├── 1630342025950-StudentMigration.ts
│ │ ├── 1630342266002-UserMigration.ts
│ │ ├── 1630347897950-StudentMigration.ts
│ │ ├── 1632333725126-ResumeMigration.ts
│ │ ├── 1635365797478-User.ts
│ │ ├── 1637591194886-StageInterview.ts
│ │ ├── 1638302439645-CourseMigration.ts
│ │ ├── 1639418471577-Indicies.ts
│ │ ├── 1639427578702-Update.ts
│ │ ├── 1639502600339-Student.ts
│ │ ├── 1642884123347-ResumeSelectCourses.ts
│ │ ├── 1643481312933-Task.ts
│ │ ├── 1643550350939-LoginState.ts
│ │ ├── 1643926895264-Notifications.ts
│ │ ├── 1644695410918-NotificationConnection.ts
│ │ ├── 1645364514538-RepositoryEvent.ts
│ │ ├── 1645654601903-Opportunitites.ts
│ │ ├── 1647103154082-CrossCheckScheduling.ts
│ │ ├── 1647175301446-TaskSolutionConstraint.ts
│ │ ├── 1647550751147-NotificationType.ts
│ │ ├── 1647885219936-LoginStateUserId.ts
│ │ ├── 1649505252996-CourseLogo.ts
│ │ ├── 1649868994688-CourseLogo.ts
│ │ ├── 1650652882300-DiscordChannel.ts
│ │ ├── 1652870756742-Resume.ts
│ │ ├── 1656326258991-History.ts
│ │ ├── 1661034658479-Feedback.ts
│ │ ├── 1661087975938-Discipline.ts
│ │ ├── 1661106736439-Disciplines.ts
│ │ ├── 1661107174477-Disciplines.ts
│ │ ├── 1661616212488-NotificationCategory.ts
│ │ ├── 1662275601017-CourseTask.ts
│ │ ├── 1664183799115-CourseEvent.ts
│ │ ├── 1666348642811-TaskCriteria.ts
│ │ ├── 1666621080327-TaskSolutionResult.ts
│ │ ├── 1671475396333-Tasks.ts
│ │ ├── 1672142743107-TeamDistribution.ts
│ │ ├── 1672386450861-TeamDistribution.ts
│ │ ├── 1673090827105-TaskVerification.ts
│ │ ├── 1673692838338-User.ts
│ │ ├── 1674128274839-Team.ts
│ │ ├── 1674377676805-TeamDistributionStudent.ts
│ │ ├── 1674755854609-Resume.ts
│ │ ├── 1675245424426-UserGroup.ts
│ │ ├── 1675345245770-Course.ts
│ │ ├── 1676139987317-User.ts
│ │ ├── 1685197747051-MentorRegistry.ts
│ │ ├── 1686657350908-InterviewScore.ts
│ │ ├── 1687009744110-Prompt.ts
│ │ ├── 1691520611773-Temperature.ts
│ │ ├── 1691524327332-Temperature.ts
│ │ ├── 1693930286280-CourseUsersActivist.ts
│ │ ├── 1699808604000-AddMinStudentPerMentorColumnToCourse.ts
│ │ ├── 1700391857109-Obfuscation.ts
│ │ ├── 1712137476312-Course.ts
│ │ ├── 1730926720293-CourseTask.ts
│ │ ├── 1734874453585-Contributor.ts
│ │ ├── 1736458672717-Course.ts
│ │ ├── 1738250779923-CoursePersonalMentoringDates.ts
│ │ ├── 1747380525126-CourseTaskInterviewCreatingPairs.ts
│ │ └── index.ts
│ ├── models
│ │ ├── alert.ts
│ │ ├── certificate.ts
│ │ ├── contributor.ts
│ │ ├── course.ts
│ │ ├── courseEvent.ts
│ │ ├── courseManager.ts
│ │ ├── courseTask.ts
│ │ ├── courseUser.ts
│ │ ├── data
│ │ │ ├── available-languages.data.ts
│ │ │ ├── index.ts
│ │ │ └── language-levels.data.ts
│ │ ├── discipline.ts
│ │ ├── discordServer.ts
│ │ ├── event.ts
│ │ ├── feedback.ts
│ │ ├── history.ts
│ │ ├── index.ts
│ │ ├── loginState.ts
│ │ ├── mentor.ts
│ │ ├── mentorRegistry.ts
│ │ ├── notification.ts
│ │ ├── notificationChannel.ts
│ │ ├── notificationChannelSettings.ts
│ │ ├── notificationUserConnection.ts
│ │ ├── notificationUserSettings.ts
│ │ ├── privateFeedback.ts
│ │ ├── profilePermissions.ts
│ │ ├── prompt.ts
│ │ ├── registry.ts
│ │ ├── repositoryEvent.ts
│ │ ├── resume.ts
│ │ ├── session.ts
│ │ ├── stageInterview.ts
│ │ ├── stageInterviewFeedback.ts
│ │ ├── stageInterviewStudent.ts
│ │ ├── student-feedback.ts
│ │ ├── student.ts
│ │ ├── task.ts
│ │ ├── taskArtefact.ts
│ │ ├── taskChecker.ts
│ │ ├── taskCriteria.ts
│ │ ├── taskInterviewResult.ts
│ │ ├── taskInterviewStudent.ts
│ │ ├── taskResult.ts
│ │ ├── taskSolution.ts
│ │ ├── taskSolutionChecker.ts
│ │ ├── taskSolutionResult.ts
│ │ ├── taskVerification.ts
│ │ ├── team.ts
│ │ ├── teamDistribution.ts
│ │ ├── teamDistributionStudent.ts
│ │ ├── user.ts
│ │ └── userGroup.ts
│ ├── repositories
│ │ ├── courseTask.repository.ts
│ │ ├── crossCheck.repository.ts
│ │ ├── feedback.repository.ts
│ │ ├── interview.repository.ts
│ │ ├── mentor.repository.ts
│ │ ├── mentorRegistry.repository.ts
│ │ ├── repositoryEvent.repository.ts
│ │ ├── stageInterview.repository.ts
│ │ ├── stageInterviewFeedback.repository.ts
│ │ ├── student.repository.ts
│ │ └── user.repository.ts
│ ├── reset.d.ts
│ ├── routes
│ │ ├── checks
│ │ │ ├── getBadComment.ts
│ │ │ ├── getMaxScoreCheckers.ts
│ │ │ └── index.ts
│ │ ├── common.ts
│ │ ├── course
│ │ │ ├── certificates.ts
│ │ │ ├── crossCheck
│ │ │ │ ├── createCompletion.ts
│ │ │ │ ├── createDistribution.ts
│ │ │ │ ├── createMessage.ts
│ │ │ │ ├── createResult.ts
│ │ │ │ ├── createSolution.ts
│ │ │ │ ├── deleteSolution.ts
│ │ │ │ ├── getAssignments.ts
│ │ │ │ ├── getResult.ts
│ │ │ │ ├── getSolution.ts
│ │ │ │ ├── getTaskDetails.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── updateMessage.ts
│ │ │ ├── events.ts
│ │ │ ├── index.ts
│ │ │ ├── interviews.ts
│ │ │ ├── mentor.ts
│ │ │ ├── repository.ts
│ │ │ ├── schedule.ts
│ │ │ ├── score
│ │ │ │ ├── createMultipleScores.ts
│ │ │ │ ├── createSingleScore.ts
│ │ │ │ ├── getScoreByStudent.ts
│ │ │ │ ├── getScoreCsv.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── recalculateScore.ts
│ │ │ ├── stageInterview
│ │ │ │ ├── cancelInterview.ts
│ │ │ │ ├── createFeedback.ts
│ │ │ │ ├── createInterview.ts
│ │ │ │ ├── createInterviews.ts
│ │ │ │ ├── getFeedback.ts
│ │ │ │ ├── getInterviewStudent.ts
│ │ │ │ ├── getInterviewerStudents.ts
│ │ │ │ ├── getInterviews.ts
│ │ │ │ ├── index.ts
│ │ │ │ └── updateInterview.ts
│ │ │ ├── student.ts
│ │ │ ├── students.ts
│ │ │ ├── taskArtefact.ts
│ │ │ ├── taskVerifications.ts
│ │ │ └── tasks
│ │ │ │ ├── createCourseTaskDistribution.ts
│ │ │ │ ├── getCourseTasksDetails.ts
│ │ │ │ └── index.ts
│ │ ├── feedback.ts
│ │ ├── file
│ │ │ ├── index.ts
│ │ │ └── upload.ts
│ │ ├── guards.ts
│ │ ├── index.ts
│ │ ├── logging.ts
│ │ ├── me.ts
│ │ ├── middlewares.ts
│ │ ├── profile
│ │ │ ├── __test__
│ │ │ │ └── permissions.test.ts
│ │ │ ├── index.ts
│ │ │ ├── info.ts
│ │ │ ├── me.ts
│ │ │ ├── mentor-stats.ts
│ │ │ ├── permissions.ts
│ │ │ ├── public-feedback.ts
│ │ │ ├── stage-interview-feedback.ts
│ │ │ ├── student-stats.ts
│ │ │ └── user-info.ts
│ │ ├── registry
│ │ │ └── index.ts
│ │ ├── repository
│ │ │ ├── events.ts
│ │ │ └── index.ts
│ │ ├── task
│ │ │ └── index.ts
│ │ ├── taskVerification
│ │ │ └── index.ts
│ │ ├── tasks
│ │ │ └── index.ts
│ │ ├── users
│ │ │ └── index.ts
│ │ ├── utils.ts
│ │ └── validators.ts
│ ├── rules
│ │ ├── __tests__
│ │ │ └── mentors.test.ts
│ │ ├── index.ts
│ │ ├── interviews.ts
│ │ ├── mentors.ts
│ │ ├── name.ts
│ │ └── types.ts
│ ├── schedule.ts
│ └── services
│ │ ├── aws.service.ts
│ │ ├── check.service.ts
│ │ ├── course.service.ts
│ │ ├── crossCheck.service.ts
│ │ ├── distribution
│ │ ├── __tests__
│ │ │ ├── crossCheck.test.ts
│ │ │ ├── crossMentor.test.ts
│ │ │ └── shuffle.test.ts
│ │ ├── crossCheckDistribution.service.ts
│ │ ├── crossMentorDistribution.service.ts
│ │ ├── index.ts
│ │ └── shuffle.ts
│ │ ├── github.service.ts
│ │ ├── index.ts
│ │ ├── interview.service.ts
│ │ ├── notification.service.ts
│ │ ├── operationResult.ts
│ │ ├── repository.service.ts
│ │ ├── score
│ │ ├── index.ts
│ │ └── score.service.ts
│ │ ├── stageInterview.service.ts
│ │ ├── student.service.ts
│ │ ├── taskResults.service.ts
│ │ ├── taskVerification.service.ts
│ │ ├── tasks.service.ts
│ │ └── user.service.ts
├── swaggerDef.js
└── tsconfig.json
├── setup
├── backup-local.sql
├── cdk
│ ├── App.ts
│ ├── DockerFunctionConstruct.ts
│ ├── Stack.ts
│ ├── cdk.json
│ ├── package-lock.json
│ └── package.json
├── docker-compose.yml
├── dump-local.sh
├── dump.sh
├── nginx
│ └── nginx.conf
├── restore-local.sh
└── restore.sh
├── tools
├── bumblebee
│ ├── .env.example
│ ├── .gitignore
│ ├── Dockerfile
│ ├── LICENSE
│ ├── README.md
│ ├── docker-compose.yml
│ ├── package-lock.json
│ ├── package.json
│ └── src
│ │ ├── constants
│ │ ├── defaults.js
│ │ └── discord-bridge.js
│ │ ├── discord
│ │ ├── discord-bridge.js
│ │ ├── events
│ │ │ ├── index.js
│ │ │ ├── message-delete.js
│ │ │ ├── message-update.js
│ │ │ ├── message.js
│ │ │ └── ready.js
│ │ ├── filters.js
│ │ ├── index.js
│ │ ├── time-logger.js
│ │ └── utils.js
│ │ ├── index.js
│ │ ├── lib
│ │ └── common.js
│ │ └── telegram
│ │ ├── events
│ │ ├── help.js
│ │ ├── index.js
│ │ ├── ping.js
│ │ └── start.js
│ │ ├── index.js
│ │ └── telegram-bot.js
└── sloths
│ ├── .env.example
│ ├── .eslintrc.cjs
│ ├── .gitignore
│ ├── .prettierrc
│ ├── README.md
│ ├── env.d.ts
│ ├── index.html
│ ├── package-lock.json
│ ├── package.json
│ ├── public
│ ├── cdn
│ │ ├── cleaned
│ │ │ ├── codewars.svg
│ │ │ ├── congrats.svg
│ │ │ ├── deadline.svg
│ │ │ └── filelist.json
│ │ └── stickers
│ │ │ ├── activist
│ │ │ ├── image.svg
│ │ │ └── metadata.json
│ │ │ ├── codewars
│ │ │ ├── image.svg
│ │ │ └── metadata.json
│ │ │ ├── congrats
│ │ │ ├── image.svg
│ │ │ └── metadata.json
│ │ │ └── metadata.json
│ ├── favicon
│ │ ├── favicon-32x32.png
│ │ └── favicon.ico
│ └── img
│ │ ├── catalog
│ │ ├── download-dark.svg
│ │ └── download-light.svg
│ │ ├── guess
│ │ ├── bg.svg
│ │ ├── painted
│ │ │ ├── 01.svg
│ │ │ ├── 02.svg
│ │ │ ├── 03.svg
│ │ │ ├── 04.svg
│ │ │ ├── 05.svg
│ │ │ ├── 06.svg
│ │ │ ├── 07.svg
│ │ │ ├── 08.svg
│ │ │ ├── 09.svg
│ │ │ ├── 10.svg
│ │ │ ├── 11.svg
│ │ │ ├── 12.svg
│ │ │ ├── 13.svg
│ │ │ ├── 14.svg
│ │ │ ├── 15.svg
│ │ │ ├── 16.svg
│ │ │ ├── 17.svg
│ │ │ ├── 18.svg
│ │ │ ├── 19.svg
│ │ │ ├── 20.svg
│ │ │ ├── 21.svg
│ │ │ ├── 22.svg
│ │ │ ├── 23.svg
│ │ │ ├── 24.svg
│ │ │ ├── 25.svg
│ │ │ ├── 26.svg
│ │ │ ├── 27.svg
│ │ │ ├── 28.svg
│ │ │ ├── 29.svg
│ │ │ ├── 30.svg
│ │ │ ├── 31.svg
│ │ │ ├── 32.svg
│ │ │ ├── 33.svg
│ │ │ ├── 34.svg
│ │ │ ├── 35.svg
│ │ │ ├── 36.svg
│ │ │ ├── 37.svg
│ │ │ ├── 38.svg
│ │ │ ├── 39.svg
│ │ │ └── 40.svg
│ │ └── winner2.svg
│ │ ├── home
│ │ ├── catalog-down.svg
│ │ ├── catalog-up.svg
│ │ ├── create.svg
│ │ ├── guess.svg
│ │ ├── memory.svg
│ │ ├── merch.svg
│ │ └── sloth.svg
│ │ ├── logo.svg
│ │ ├── memory
│ │ ├── memory-level-junior.svg
│ │ ├── memory-level-middle.svg
│ │ ├── memory-level-senior.svg
│ │ ├── memory-sprite.svg
│ │ ├── reload-dark.svg
│ │ ├── reload-light.svg
│ │ └── winner1.svg
│ │ ├── merch
│ │ ├── hoodie.png
│ │ ├── merch-cleaned.svg
│ │ ├── merch-original.svg
│ │ ├── mug.png
│ │ ├── thermo.png
│ │ └── tshirt.png
│ │ ├── photo
│ │ ├── ogimly.png
│ │ ├── vanet.png
│ │ └── wiijoy.png
│ │ ├── preview.svg
│ │ └── team
│ │ └── wwt.svg
│ ├── src
│ ├── App.vue
│ ├── assets
│ │ ├── backgrounds
│ │ │ ├── bg-404-dark.svg
│ │ │ ├── bg-404-light.svg
│ │ │ ├── bg-about-dark.svg
│ │ │ ├── bg-about-light.svg
│ │ │ ├── bg-catalog-dark.svg
│ │ │ ├── bg-catalog-light.svg
│ │ │ ├── bg-create-dark.svg
│ │ │ ├── bg-create-light.svg
│ │ │ ├── bg-footer-dark.svg
│ │ │ ├── bg-footer-light.svg
│ │ │ ├── bg-guess-dark.svg
│ │ │ ├── bg-guess-light.svg
│ │ │ ├── bg-home-dark.svg
│ │ │ ├── bg-home-light.svg
│ │ │ ├── bg-memory-dark.svg
│ │ │ ├── bg-memory-light.svg
│ │ │ ├── bg-merch-dark.svg
│ │ │ ├── bg-merch-light.svg
│ │ │ ├── bg-stars-dark.svg
│ │ │ └── bg-stars-light.svg
│ │ ├── fonts
│ │ │ ├── Arial-Black.woff
│ │ │ ├── Arial-Black.woff2
│ │ │ ├── NunitoSans-Black.woff
│ │ │ ├── NunitoSans-Black.woff2
│ │ │ ├── NunitoSans-Bold.woff
│ │ │ ├── NunitoSans-Bold.woff2
│ │ │ ├── NunitoSans-Light.woff
│ │ │ ├── NunitoSans-Light.woff2
│ │ │ ├── NunitoSans-Regular.woff
│ │ │ └── NunitoSans-Regular.woff2
│ │ ├── icons
│ │ │ ├── 404
│ │ │ │ └── 404.svg
│ │ │ ├── btn
│ │ │ │ ├── center-square-black.svg
│ │ │ │ ├── center-square.svg
│ │ │ │ ├── check-circle-fill.svg
│ │ │ │ ├── check-circle.svg
│ │ │ │ ├── check-square-black.svg
│ │ │ │ ├── check-square.svg
│ │ │ │ ├── clipboard-black.svg
│ │ │ │ ├── clipboard.svg
│ │ │ │ ├── dash-square-black.svg
│ │ │ │ ├── dash-square.svg
│ │ │ │ ├── download-black.svg
│ │ │ │ ├── download.svg
│ │ │ │ ├── plus-square-black.svg
│ │ │ │ └── plus-square.svg
│ │ │ ├── loader
│ │ │ │ └── loader-point.svg
│ │ │ ├── rs-school.png
│ │ │ ├── sounds
│ │ │ │ ├── sound-dark-off.svg
│ │ │ │ ├── sound-dark-on.svg
│ │ │ │ ├── sound-light-off.svg
│ │ │ │ └── sound-light-on.svg
│ │ │ └── themes
│ │ │ │ ├── dark.svg
│ │ │ │ └── light.svg
│ │ ├── locales
│ │ │ └── en.json
│ │ ├── sounds
│ │ │ ├── fail.mp3
│ │ │ ├── flip.mp3
│ │ │ ├── ovation.mp3
│ │ │ ├── sad-trombone.mp3
│ │ │ ├── slide.mp3
│ │ │ ├── success.mp3
│ │ │ └── ta-da.mp3
│ │ └── styles
│ │ │ ├── base.css
│ │ │ ├── fonts.css
│ │ │ ├── main.css
│ │ │ └── variables.css
│ ├── common
│ │ ├── const.ts
│ │ └── types.ts
│ ├── components
│ │ ├── about
│ │ │ ├── AboutSection.vue
│ │ │ └── AboutTeammate.vue
│ │ ├── background
│ │ │ └── BackgroundView.vue
│ │ ├── buttons
│ │ │ ├── CustomBtn.vue
│ │ │ ├── IconBtn.vue
│ │ │ └── ImageBtn.vue
│ │ ├── catalog
│ │ │ ├── SlothCard.vue
│ │ │ └── SlothInfo.vue
│ │ ├── controls-list
│ │ │ ├── ControlsList.vue
│ │ │ ├── PaginationList.vue
│ │ │ ├── SearchText.vue
│ │ │ ├── SortingList.vue
│ │ │ └── TagCloud.vue
│ │ ├── footer
│ │ │ └── FooterView.vue
│ │ ├── guess
│ │ │ └── GuessInfo.vue
│ │ ├── header
│ │ │ └── HeaderView.vue
│ │ ├── home
│ │ │ ├── HomeAbout.vue
│ │ │ ├── HomeCatalog.vue
│ │ │ └── HomeCategory.vue
│ │ ├── loader
│ │ │ └── LoaderView.vue
│ │ ├── memory
│ │ │ ├── GameField.vue
│ │ │ └── MemoryInfo.vue
│ │ ├── mixins
│ │ │ └── sort-mixin.ts
│ │ ├── modal
│ │ │ ├── AlertModal.vue
│ │ │ └── ModalWindow.vue
│ │ └── switchers
│ │ │ ├── SoundSwitcher.vue
│ │ │ └── ThemeSwitcher.vue
│ ├── i18n.ts
│ ├── main.ts
│ ├── router
│ │ └── index.ts
│ ├── services
│ │ ├── error-handler.ts
│ │ └── sloths-service.ts
│ ├── shims-vue.d.ts
│ ├── stores
│ │ ├── alert-modal.ts
│ │ ├── audio-on.ts
│ │ ├── cleaned.ts
│ │ ├── counter.ts
│ │ ├── loader.ts
│ │ ├── pages-store.ts
│ │ ├── pagination.ts
│ │ ├── search-text.ts
│ │ ├── sloth-info.ts
│ │ ├── sloths.ts
│ │ ├── sorting-list.ts
│ │ ├── tag-cloud.ts
│ │ └── theme.ts
│ ├── utils
│ │ ├── audio.ts
│ │ ├── canvas-utils.ts
│ │ ├── game-utils.ts
│ │ └── userTheme.ts
│ └── views
│ │ ├── 404.vue
│ │ ├── About.vue
│ │ ├── Catalog.vue
│ │ ├── Create.vue
│ │ ├── Guess.vue
│ │ ├── Home.vue
│ │ ├── Memory.vue
│ │ └── Merch.vue
│ ├── tsconfig.config.json
│ ├── tsconfig.json
│ └── vite.config.ts
└── turbo.json
/.dockerignore:
--------------------------------------------------------------------------------
1 | client/.next/cache
2 | client/.next/static
3 | client/.turbo
4 | node_modules
5 | npm-debug.log
6 | .turbo
7 |
--------------------------------------------------------------------------------
/.editorconfig:
--------------------------------------------------------------------------------
1 | # http://editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | charset = utf-8
7 | indent_style = space
8 | indent_size = 2
9 | end_of_line = lf
10 | insert_final_newline = true
11 | trim_trailing_whitespace = true
12 |
13 | [*.md]
14 | insert_final_newline = false
15 | trim_trailing_whitespace = false
16 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | # don't ever lint node_modules
2 | node_modules
3 | # don't lint build output (make sure it's set to your correct build folder name)
4 | dist
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/data-issue-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 🗃 Data issue
3 | about: Create a issue to fix data
4 | title: ''
5 | labels: data issue
6 | ---
7 |
8 | **Course**
9 | Specify your course (e.g. rs-2019-q1)
10 |
11 | **What is wrong**
12 | Describe data issue
13 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: 🚀 Feature request
3 | about: Request a feature to implement
4 | title: ''
5 | labels: feature
6 | ---
7 |
8 | **Describe the feature**
9 | Please describe the requested feature in details.
10 |
11 | **Additional context**
12 | Add any other context about the feature here.
13 |
--------------------------------------------------------------------------------
/.github/auto-label.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "code:client": ["client/"],
4 | "code:server": ["server/"],
5 | "⛓ dependencies": "**/package.json"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/.github/pull_request_template.md:
--------------------------------------------------------------------------------
1 | [Pull Request Guidelines](https://github.com/rolling-scopes/rsschool-app/blob/master/CONTRIBUTING.md#pull-requests)
2 |
3 | **Issue**:
4 | _Link to the relevant GitHub Issue (e.g., `#123` for issue number 123)._
5 |
6 | **Description**:
7 | _Please provide a description of the changes in this Pull Request. Include screenshots or GIFs if applicable. The description should clearly explain the purpose of this PR._
8 |
9 | **Self-Check**:
10 |
11 | - [ ] Database migration added (if required)
12 | - [ ] Changes tested locally
13 |
--------------------------------------------------------------------------------
/.github/workflows/renovate.yml:
--------------------------------------------------------------------------------
1 | name: Renovate
2 | on:
3 | schedule:
4 | # once a month
5 | - cron: '0 0 1 * *'
6 | workflow_dispatch:
7 | jobs:
8 | renovate:
9 | runs-on: ubuntu-latest
10 | steps:
11 | - name: Checkout
12 | uses: actions/checkout@v4
13 | - name: Self-hosted Renovate
14 | uses: renovatebot/github-action@v34.82.0
15 | with:
16 | configurationFile: renovate.json
17 | token: ${{ secrets.RENOVATE_TOKEN }}
18 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .env
3 | .history/
4 | .idea/
5 | .next/
6 | .sentryclirc
7 | .swc/
8 | .turbo
9 | .vscode
10 | app/
11 | coverage
12 | dist/
13 | node_modules/
14 | out
15 | playwright-report/
16 | reports/*.xml
17 | setup/backup.sql
18 | setup/cdk/cdk.out
19 | test-results/
20 | client/tsconfig.tsbuildinfo
21 |
--------------------------------------------------------------------------------
/.prettierignore:
--------------------------------------------------------------------------------
1 | client/src/.next
2 | client/.next
3 | client/dist
4 | server/dist
5 | nestjs/dist
6 | client/src/api/
7 | client/playwright-report/
8 | package-lock.json
9 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "all",
3 | "tabWidth": 2,
4 | "semi": true,
5 | "singleQuote": true,
6 | "printWidth": 120,
7 | "arrowParens": "avoid"
8 | }
9 |
--------------------------------------------------------------------------------
/client/.dockerignore:
--------------------------------------------------------------------------------
1 | .next/cache
2 | .next/static
3 | node_modules
4 | .turbo
5 |
--------------------------------------------------------------------------------
/client/.env.example:
--------------------------------------------------------------------------------
1 | RSSHCOOL_UI_GCP_MAPS_API_KEY=
2 |
--------------------------------------------------------------------------------
/client/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:20-alpine
2 |
3 | EXPOSE 8080
4 |
5 | ENV NODE_ENV production
6 | ENV NODE_PORT 8080
7 |
8 | WORKDIR /app
9 |
10 | COPY client/next.config.mjs /app/client/next.config.mjs
11 | COPY client/next.config.prod.mjs /app/client/next.config.prod.mjs
12 | COPY client/package.json /app/client/package.json
13 | COPY client/public /app/client/public
14 |
15 | COPY package.json /app
16 | COPY package-lock.json /app
17 |
18 | RUN npm ci --production --no-optional
19 |
20 | COPY client/.next /app/client/.next
21 |
22 | CMD cd /app/client && npm run prod
23 |
--------------------------------------------------------------------------------
/client/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import testingLibrary from 'eslint-plugin-testing-library';
2 | import defaultConfig from '../eslint.config.mjs';
3 |
4 | export default [
5 | ...defaultConfig,
6 | {
7 | ...testingLibrary.configs['flat/react'],
8 | files: ['**/__tests__/**/*.ts?(x)', '**/?(*.)+(spec|test).ts?(x)'],
9 | },
10 | ];
11 |
--------------------------------------------------------------------------------
/client/next-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | ///
3 |
4 | // NOTE: This file should not be edited
5 | // see https://nextjs.org/docs/basic-features/typescript for more information.
6 |
--------------------------------------------------------------------------------
/client/next.config.prod.mjs:
--------------------------------------------------------------------------------
1 | const isProd = process.env.NODE_ENV === 'production';
2 |
3 | const nextConfig = {
4 | serverRuntimeConfig: {
5 | rsHost: process.env.RS_HOST || 'http://localhost:3000',
6 | },
7 | assetPrefix: isProd ? 'https://cdn.rs.school' : '',
8 | env: {
9 | BUILD_VERSION: process.env.BUILD_VERSION || '0.0.0.0.0',
10 | APP_VERSION: process.env.APP_VERSION,
11 | RSSHCOOL_UI_GCP_MAPS_API_KEY: process.env.RSSHCOOL_UI_GCP_MAPS_API_KEY,
12 | CDN_HOST: process.env.CDN_HOST || '',
13 | },
14 | };
15 |
16 | export default nextConfig;
17 |
--------------------------------------------------------------------------------
/client/public/static/empty.txt:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/client/public/static/empty.txt
--------------------------------------------------------------------------------
/client/public/static/images/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/client/public/static/images/favicon.ico
--------------------------------------------------------------------------------
/client/public/static/images/job/dot.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/client/public/static/images/job/dot.png
--------------------------------------------------------------------------------
/client/public/static/images/logo-rsschool2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/client/public/static/images/logo-rsschool2.png
--------------------------------------------------------------------------------
/client/public/static/images/logo-rsschool3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/client/public/static/images/logo-rsschool3.png
--------------------------------------------------------------------------------
/client/public/static/images/logo_rs.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/client/public/static/images/logo_rs.png
--------------------------------------------------------------------------------
/client/public/static/images/rs-hero.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/client/public/static/images/rs-hero.png
--------------------------------------------------------------------------------
/client/public/static/images/united-kingdom.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/client/public/static/images/united-kingdom.png
--------------------------------------------------------------------------------
/client/src/__mocks__/axios.js:
--------------------------------------------------------------------------------
1 | import mockAxios from 'jest-mock-axios';
2 |
3 | export default mockAxios;
4 |
--------------------------------------------------------------------------------
/client/src/api/.gitignore:
--------------------------------------------------------------------------------
1 | wwwroot/*.js
2 | node_modules
3 | typings
4 | dist
5 |
--------------------------------------------------------------------------------
/client/src/api/.npmignore:
--------------------------------------------------------------------------------
1 | # empty npmignore to ensure all required files (e.g., in the dist folder) are published by npm
--------------------------------------------------------------------------------
/client/src/api/.openapi-generator/FILES:
--------------------------------------------------------------------------------
1 | .gitignore
2 | .npmignore
3 | api.ts
4 | base.ts
5 | common.ts
6 | configuration.ts
7 | git_push.sh
8 | index.ts
9 |
--------------------------------------------------------------------------------
/client/src/api/.openapi-generator/VERSION:
--------------------------------------------------------------------------------
1 | 5.4.0
--------------------------------------------------------------------------------
/client/src/api/index.ts:
--------------------------------------------------------------------------------
1 | /* tslint:disable */
2 | /* eslint-disable */
3 | /**
4 | *
5 | * No description provided (generated by Openapi Generator https://github.com/openapitools/openapi-generator)
6 | *
7 | * The version of the OpenAPI document: 1.0.0
8 | *
9 | *
10 | * NOTE: This class is auto generated by OpenAPI Generator (https://openapi-generator.tech).
11 | * https://openapi-generator.tech
12 | * Do not edit the class manually.
13 | */
14 |
15 |
16 | export * from "./api";
17 | export * from "./configuration";
18 |
19 |
--------------------------------------------------------------------------------
/client/src/components/CountBadge/index.tsx:
--------------------------------------------------------------------------------
1 | export { default as CountBadge } from './CountBadge';
2 |
--------------------------------------------------------------------------------
/client/src/components/Footer/index.tsx:
--------------------------------------------------------------------------------
1 | export { FooterLayout } from './FooterLayout';
2 |
--------------------------------------------------------------------------------
/client/src/components/Forms/CommentInput.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Input, Form } from 'antd';
3 |
4 | export function CommentInput(props: { [key: string]: any; notRequired?: boolean }) {
5 | const { notRequired, ...otherProps } = props;
6 | return (
7 |
13 |
14 |
15 | );
16 | }
17 |
--------------------------------------------------------------------------------
/client/src/components/Forms/index.ts:
--------------------------------------------------------------------------------
1 | export * from './GdprCheckbox';
2 | export * from './ScoreInput';
3 | export * from './CommentInput';
4 | export * from './CourseTaskSelect';
5 | export * from './ModalForm';
6 | export * from './LocationSelect';
7 |
--------------------------------------------------------------------------------
/client/src/components/GithubAvatar.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Avatar } from 'antd';
3 | import { CDN_AVATARS_URL } from 'configs/cdn';
4 |
5 | type Props = {
6 | githubId?: string;
7 | size: 24 | 32 | 48 | 96;
8 | style?: React.CSSProperties;
9 | alt?: string;
10 | };
11 |
12 | export function GithubAvatar({ githubId, size, style }: Props) {
13 | if (!githubId || githubId.startsWith('gdpr-')) {
14 | return ;
15 | }
16 | return ;
17 | }
18 |
--------------------------------------------------------------------------------
/client/src/components/Icons/index.tsx:
--------------------------------------------------------------------------------
1 | export * from './CourseIcon';
2 | export * from './DeadlineIcon';
3 | export * from './DiscordFilled';
4 | export * from './DiscordOutlined';
5 | export * from './HealthMask';
6 | export * from './LinkedInIcon';
7 | export * from './ScoreIcon';
8 | export * from './TelegramIcon';
9 | export * from './GitHubLogoIcon';
10 | export * from './RSLogoIcon';
11 |
--------------------------------------------------------------------------------
/client/src/components/Profile/__test__/__snapshots__/CoreJsIviewsModal.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`CoreJsIviewsModal Should render correctly 1`] = ``;
4 |
--------------------------------------------------------------------------------
/client/src/components/Profile/__test__/__snapshots__/MentorStatsModal.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`MentorStatsModal Should render correctly 1`] = ``;
4 |
--------------------------------------------------------------------------------
/client/src/components/Profile/__test__/__snapshots__/PreScreeningIviewModal.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`PreScreeningIviewModal Should render correctly 1`] = ``;
4 |
--------------------------------------------------------------------------------
/client/src/components/Profile/__test__/__snapshots__/PublicFeedbackModal.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`PublicFeedbackModal Should render correctly 1`] = ``;
4 |
--------------------------------------------------------------------------------
/client/src/components/Profile/__test__/__snapshots__/StudentStatsModal.test.tsx.snap:
--------------------------------------------------------------------------------
1 | // Jest Snapshot v1, https://goo.gl/fbAQLP
2 |
3 | exports[`StudentStatsModal Should render correctly 1`] = ``;
4 |
--------------------------------------------------------------------------------
/client/src/components/SolidarityUkraine.tsx:
--------------------------------------------------------------------------------
1 | import Image from 'next/image';
2 |
3 | export function SolidarityUkraine() {
4 | return ;
5 | }
6 |
--------------------------------------------------------------------------------
/client/src/components/Student/index.ts:
--------------------------------------------------------------------------------
1 | export { AssignStudentModal } from './AssignStudentModal';
2 | export { DashboardDetails } from './DashboardDetails';
3 |
--------------------------------------------------------------------------------
/client/src/components/Table/index.ts:
--------------------------------------------------------------------------------
1 | export * from './renderers';
2 | export * from './sorters';
3 | export * from './columns';
4 | export { PersonCell } from './PersonCell';
5 |
--------------------------------------------------------------------------------
/client/src/components/common/CustomPopconfirm.tsx:
--------------------------------------------------------------------------------
1 | import { Popconfirm, PopconfirmProps } from 'antd';
2 |
3 | export const CustomPopconfirm = ({ placement, ...props }: PopconfirmProps) => {
4 | return ;
5 | };
6 |
--------------------------------------------------------------------------------
/client/src/components/withSession.tsx:
--------------------------------------------------------------------------------
1 | import { CourseRole } from 'services/models';
2 |
3 | export interface CourseInfo {
4 | mentorId?: number;
5 | studentId?: number;
6 | roles: CourseRole[];
7 | isExpelled?: boolean;
8 | }
9 |
10 | export interface Session {
11 | id: number;
12 | githubId: string;
13 | isAdmin: boolean;
14 | isHirer: boolean;
15 | courses: { [courseId: string]: CourseInfo | undefined };
16 | }
17 |
--------------------------------------------------------------------------------
/client/src/configs/cdn.ts:
--------------------------------------------------------------------------------
1 | export const CDN_AVATARS_URL = 'https://cdn.rs.school/avatars';
2 |
--------------------------------------------------------------------------------
/client/src/configs/discord-integration.ts:
--------------------------------------------------------------------------------
1 | const isDevMode = process.env.NODE_ENV !== 'production';
2 | const clientId = isDevMode ? '625945676009963521' : '978920245743976448';
3 | const redirectUrl = isDevMode ? 'http://localhost:3000/profile' : 'https://app.rs.school/profile';
4 |
5 | export default {
6 | api: {
7 | auth: `https://discord.com/api/oauth2/authorize?client_id=${clientId}&redirect_uri=${encodeURIComponent(
8 | redirectUrl,
9 | )}&response_type=token&scope=identify`,
10 | me: 'https://discordapp.com/api/users/@me',
11 | },
12 | };
13 |
--------------------------------------------------------------------------------
/client/src/configs/gcp.ts:
--------------------------------------------------------------------------------
1 | export const mapsApiKey = process.env.RSSHCOOL_UI_GCP_MAPS_API_KEY;
2 |
--------------------------------------------------------------------------------
/client/src/configs/registry.ts:
--------------------------------------------------------------------------------
1 | import { Session } from 'components/withSession';
2 | import { Course } from 'services/models';
3 |
4 | export const TYPES = {
5 | MENTOR: 'mentor',
6 | STUDENT: 'student',
7 | };
8 |
9 | export type Props = {
10 | courses?: Course[];
11 | session: Session;
12 | };
13 |
--------------------------------------------------------------------------------
/client/src/data/english.ts:
--------------------------------------------------------------------------------
1 | export const ENGLISH_LEVELS = ['A0', 'A1', 'A1+', 'A2', 'A2+', 'B1', 'B1+', 'B2', 'B2+', 'C1', 'C1+', 'C2'] as const;
2 |
--------------------------------------------------------------------------------
/client/src/data/index.ts:
--------------------------------------------------------------------------------
1 | import { EVENT_TYPES_MAP } from './eventTypes';
2 | import { TASK_TYPES_MAP } from './taskTypes';
3 |
4 | export const TASK_EVENT_TYPES_MAP = {
5 | ...TASK_TYPES_MAP,
6 | ...EVENT_TYPES_MAP,
7 | };
8 |
--------------------------------------------------------------------------------
/client/src/data/skills.ts:
--------------------------------------------------------------------------------
1 | export const SKILLS = [
2 | 'react',
3 | 'angular',
4 | 'unit-tests',
5 | 'jest',
6 | 'javascript-core',
7 | 'redux',
8 | 'html',
9 | 'css',
10 | 'scss',
11 | 'less',
12 | 'nestjs',
13 | ];
14 |
--------------------------------------------------------------------------------
/client/src/data/tshirts.ts:
--------------------------------------------------------------------------------
1 | export const TSHIRT_SIZES = [
2 | {
3 | id: 'xs',
4 | name: 'XS',
5 | },
6 | {
7 | id: 's',
8 | name: 'S',
9 | },
10 | {
11 | id: 'm',
12 | name: 'M',
13 | },
14 | {
15 | id: 'l',
16 | name: 'L',
17 | },
18 | {
19 | id: 'xl',
20 | name: 'XL',
21 | },
22 | {
23 | id: 'xxl',
24 | name: 'XXL',
25 | },
26 | {
27 | id: 'xxxl',
28 | name: 'XXXL',
29 | },
30 | ];
31 |
--------------------------------------------------------------------------------
/client/src/domain/course.test.ts:
--------------------------------------------------------------------------------
1 | import { CourseTaskDto } from 'api';
2 | import { getTasksTotalScore } from './course';
3 |
4 | describe('getTasksTotalScore', () => {
5 | test('should calculate total score', () => {
6 | expect(
7 | getTasksTotalScore([
8 | {
9 | maxScore: 100,
10 | scoreWeight: 1,
11 | },
12 | {
13 | maxScore: 100,
14 | scoreWeight: 0.5,
15 | },
16 | ] as CourseTaskDto[]),
17 | ).toBe(100 + 50);
18 | });
19 | });
20 |
--------------------------------------------------------------------------------
/client/src/domain/course.ts:
--------------------------------------------------------------------------------
1 | import { CourseTaskDto } from 'api';
2 |
3 | export function getTasksTotalScore(courseTasks: CourseTaskDto[]) {
4 | return courseTasks.reduce((score, task) => score + (task.maxScore ?? 0) * task.scoreWeight, 0);
5 | }
6 |
--------------------------------------------------------------------------------
/client/src/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/client/src/favicon.ico
--------------------------------------------------------------------------------
/client/src/hooks/index.ts:
--------------------------------------------------------------------------------
1 | export { useModalForm } from './useModal/useModalForm';
2 | export type { ModalFormMode } from './useModal/useModalForm';
3 |
--------------------------------------------------------------------------------
/client/src/index.d.ts:
--------------------------------------------------------------------------------
1 | declare module 'mq-polyfill';
2 |
--------------------------------------------------------------------------------
/client/src/modules/AutoTest/components/TaskCardColumn/TaskCardColumn.tsx:
--------------------------------------------------------------------------------
1 | import { Space, Typography } from 'antd';
2 | import { ReactNode } from 'react';
3 |
4 | type TaskCardColumnProps = {
5 | label: string;
6 | value: ReactNode;
7 | };
8 |
9 | const { Text } = Typography;
10 |
11 | function TaskCardColumn({ label, value }: TaskCardColumnProps) {
12 | return (
13 |
14 | {label}
15 | {value}
16 |
17 | );
18 | }
19 |
20 | export default TaskCardColumn;
21 |
--------------------------------------------------------------------------------
/client/src/modules/AutoTest/hooks/index.ts:
--------------------------------------------------------------------------------
1 | export { useAttemptsMessage } from './useAttemptsMessage/useAttemptsMessage';
2 | export { useCourseTaskSubmit } from './useCourseTaskSubmit/useCourseTaskSubmit';
3 | export { useCourseTaskVerifications } from './useCourseTaskVerifications/useCourseTaskVerifications';
4 | export { useVerificationsAnswers } from './useVerificationsAnswers/useVerificationsAnswers';
5 |
--------------------------------------------------------------------------------
/client/src/modules/AutoTest/pages/index.tsx:
--------------------------------------------------------------------------------
1 | export { default as AutoTests } from './AutoTests/AutoTests';
2 | export { default as Task, type AutoTestTaskProps } from './Task/Task';
3 |
--------------------------------------------------------------------------------
/client/src/modules/Course/components/NoSubmissionAvailable/index.tsx:
--------------------------------------------------------------------------------
1 | import { Typography } from 'antd';
2 | import Link from 'next/link';
3 |
4 | export function NoSubmissionAvailable({ courseAlias }: { courseAlias: string }) {
5 | return (
6 | <>
7 | No tasks available for submission now
8 | Check start dates in Schedule
9 | >
10 | );
11 | }
12 |
--------------------------------------------------------------------------------
/client/src/modules/Course/contexts/index.ts:
--------------------------------------------------------------------------------
1 | export * from './SessionContext';
2 | export * from './ActiveCourseContext';
3 |
--------------------------------------------------------------------------------
/client/src/modules/Course/pages/CouseNoAccess/index.tsx:
--------------------------------------------------------------------------------
1 | import { CourseNoAccess } from '../../components/CourseNoAccess';
2 | import React from 'react';
3 |
4 | export function CouseNoAccessPage() {
5 | return ;
6 | }
7 |
--------------------------------------------------------------------------------
/client/src/modules/CourseManagement/components/index.ts:
--------------------------------------------------------------------------------
1 | export { SelectCourseTasks } from './SelectCourseTasks/SelectCourseTasks';
2 | export { CertificateCriteriaModal } from './CertificateCriteriaModal/CertificateCriteriaModal';
3 | export { ExpelCriteriaModal } from './ExpelCriteriaModal/ExpelCriteriaModal';
4 |
--------------------------------------------------------------------------------
/client/src/modules/CourseStatistics/components/EpamMentorsStatsCard/index.tsx:
--------------------------------------------------------------------------------
1 | export { EpamMentorsStatsCard } from './EpamMentorsStatsCard';
2 |
--------------------------------------------------------------------------------
/client/src/modules/CourseStatistics/components/MentorsCountriesCard/index.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/client/src/modules/CourseStatistics/components/MentorsCountriesCard/index.ts
--------------------------------------------------------------------------------
/client/src/modules/CourseStatistics/components/StudentsCertificatesCountriesCard/index.tsx:
--------------------------------------------------------------------------------
1 | export { StudentsCertificatesCountriesCard } from './StudentsCertificatesCountriesCard';
2 |
--------------------------------------------------------------------------------
/client/src/modules/CourseStatistics/components/StudentsCountriesCard/index.tsx:
--------------------------------------------------------------------------------
1 | export { StudentsCountriesCard } from './StudentsCountriesCard';
2 |
--------------------------------------------------------------------------------
/client/src/modules/CourseStatistics/components/StudentsEligibleForCertificationCard/index.tsx:
--------------------------------------------------------------------------------
1 | export { StudentsEligibleForCertificationCard } from './StudentsEligibleForCertificationCard';
2 |
--------------------------------------------------------------------------------
/client/src/modules/CourseStatistics/components/StudentsStatsCard/index.tsx:
--------------------------------------------------------------------------------
1 | export { StudentsStatsCard } from './StudentsStatsCard';
2 |
--------------------------------------------------------------------------------
/client/src/modules/CourseStatistics/components/StudentsWithCertificateCard/index.tsx:
--------------------------------------------------------------------------------
1 | export { StudentsWithCertificateCard } from './StudentsWithCertificateCard';
2 |
--------------------------------------------------------------------------------
/client/src/modules/CourseStatistics/components/StudentsWithMentorsCard/index.tsx:
--------------------------------------------------------------------------------
1 | export { StudentsWithMentorsCard } from './StudentsWithMentorsCard';
2 |
--------------------------------------------------------------------------------
/client/src/modules/CourseStatistics/components/TaskPerformanceCard/index.tsx:
--------------------------------------------------------------------------------
1 | export { TaskPerformanceCard } from './TaskPerformanceCard';
2 |
--------------------------------------------------------------------------------
/client/src/modules/CourseStatistics/hooks/index.ts:
--------------------------------------------------------------------------------
1 | export { useCourseStats } from './useCourseStats/useCourseStats';
2 |
--------------------------------------------------------------------------------
/client/src/modules/CourseStatistics/index.tsx:
--------------------------------------------------------------------------------
1 | export { default as CourseStatistics } from './pages/CourseStatistics';
2 |
--------------------------------------------------------------------------------
/client/src/modules/CrossCheck/components/SolutionReview/Message/index.ts:
--------------------------------------------------------------------------------
1 | export { default as Message } from './Message';
2 | export { type MessageProps } from './Message';
3 |
--------------------------------------------------------------------------------
/client/src/modules/CrossCheck/components/SolutionReview/MessageSendingPanel/index.ts:
--------------------------------------------------------------------------------
1 | export { default as MessageSendingPanel } from './MessageSendingPanel';
2 | export { type MessageSendingPanelProps } from './MessageSendingPanel';
3 |
--------------------------------------------------------------------------------
/client/src/modules/CrossCheck/components/SolutionReview/UserAvatar/index.ts:
--------------------------------------------------------------------------------
1 | export { default as UserAvatar } from './UserAvatar';
2 | export { type UserAvatarProps } from './UserAvatar';
3 |
--------------------------------------------------------------------------------
/client/src/modules/CrossCheck/components/SolutionReview/Username/index.ts:
--------------------------------------------------------------------------------
1 | export { default as Username } from './Username';
2 | export { type UsernameProps } from './Username';
3 |
--------------------------------------------------------------------------------
/client/src/modules/CrossCheck/components/SolutionReview/index.ts:
--------------------------------------------------------------------------------
1 | export { default as SolutionReview } from './SolutionReview';
2 | export { type SolutionReviewProps } from './SolutionReview';
3 |
--------------------------------------------------------------------------------
/client/src/modules/CrossCheck/components/SolutionReviewSettingsPanel/index.ts:
--------------------------------------------------------------------------------
1 | export { default as SolutionReviewSettingsPanel } from './SolutionReviewSettingsPanel';
2 | export { type SolutionReviewSettingsPanelProps } from './SolutionReviewSettingsPanel';
3 |
--------------------------------------------------------------------------------
/client/src/modules/CrossCheck/hooks/index.ts:
--------------------------------------------------------------------------------
1 | export { useSolutionReviewSettings } from './useSolutionReviewSettings';
2 |
--------------------------------------------------------------------------------
/client/src/modules/CrossCheck/hooks/useSolutionReviewSettings.ts:
--------------------------------------------------------------------------------
1 | import { useLocalStorage } from 'react-use';
2 | import { LocalStorageKey, SolutionReviewSettings } from '../constants';
3 |
4 | export function useSolutionReviewSettings(): SolutionReviewSettings {
5 | const [areContactsVisible = true, setAreContactsVisible] = useLocalStorage(
6 | LocalStorageKey.AreContactsVisible,
7 | );
8 |
9 | return { areContactsVisible, setAreContactsVisible };
10 | }
11 |
--------------------------------------------------------------------------------
/client/src/modules/CrossCheck/index.tsx:
--------------------------------------------------------------------------------
1 | export { addKeyAndIndex } from 'modules/CrossCheck/utils/addKeyAndIndex';
2 | export { EditableTable } from 'modules/CrossCheck/EditableTableForCrossCheck';
3 | export { UploadCriteriaJSON } from 'modules/CrossCheck/UploadCriteriaJSON';
4 | export { AddCriteriaForCrossCheck } from 'modules/CrossCheck/AddCriteriaForCrossCheck';
5 | export { ExportJSONButton } from 'modules/CrossCheck/ExportJSONButton';
6 | export { getCriteriaStatusColor } from 'modules/CrossCheck/utils/getCriteriaStatusColor';
7 |
--------------------------------------------------------------------------------
/client/src/modules/CrossCheck/utils/addKeyAndIndex.tsx:
--------------------------------------------------------------------------------
1 | import { CriteriaDto } from 'api';
2 |
3 | export const addKeyAndIndex = (array: CriteriaDto[]): CriteriaDto[] => {
4 | return array.map((item, index) => ({
5 | ...item,
6 | key: index.toString(),
7 | index,
8 | }));
9 | };
10 |
--------------------------------------------------------------------------------
/client/src/modules/CrossCheck/utils/getCriteriaStatusColor.ts:
--------------------------------------------------------------------------------
1 | const colors = ['transparent', 'rgba(255, 0, 0, .05)', 'rgba(0, 255, 0, .05)', 'rgba(255, 255, 0, .05)'] as const;
2 |
3 | export function getCriteriaStatusColor(score: number, maxScore?: number) {
4 | const [transparent, red, green, yellow] = colors;
5 |
6 | if (!maxScore) {
7 | return transparent;
8 | }
9 |
10 | if (score === 0) {
11 | return red;
12 | }
13 |
14 | if (score < maxScore) {
15 | return yellow;
16 | }
17 |
18 | if (score === maxScore) {
19 | return green;
20 | }
21 |
22 | return transparent;
23 | }
24 |
--------------------------------------------------------------------------------
/client/src/modules/CrossCheckPairs/pages/CrossCheckPairs/index.ts:
--------------------------------------------------------------------------------
1 | export { default as CrossCheckPairs } from './CrossCheckPairs';
2 |
--------------------------------------------------------------------------------
/client/src/modules/Home/components/RegistryBanner/index.tsx:
--------------------------------------------------------------------------------
1 | import * as React from 'react';
2 | import { Alert, Button, AlertProps } from 'antd';
3 |
4 | export function RegistryBanner(props: Partial) {
5 | return (
6 |
12 | Register as Mentor
13 |
14 | }
15 | {...props}
16 | />
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/client/src/modules/Home/components/SystemAlerts/index.tsx:
--------------------------------------------------------------------------------
1 | import { Alert } from 'antd';
2 | import type { AlertDto } from 'api';
3 | import React from 'react';
4 |
5 | type Props = {
6 | alerts: AlertDto[];
7 | };
8 |
9 | export function SystemAlerts({ alerts }: Props) {
10 | return (
11 | <>
12 | {alerts.map(({ text, type }) => {
13 | const alertType = type === 'warn' ? 'warning' : type;
14 | return ;
15 | })}
16 | >
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/client/src/modules/Home/data/loadHomeData.ts:
--------------------------------------------------------------------------------
1 | import { CoursesTasksApi } from 'api';
2 | import { CourseService } from 'services/course';
3 |
4 | export async function loadHomeData(courseId: number, githubId: string) {
5 | const [studentSummary, { data: courseTasks }] = await Promise.all([
6 | new CourseService(courseId).getStudentSummary(githubId),
7 | new CoursesTasksApi().getCourseTasks(courseId),
8 | ]);
9 | return {
10 | studentSummary,
11 | courseTasks: courseTasks.map(t => ({ id: t.id })),
12 | };
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/modules/Interview/Student/components/NoInterviewsAlert.tsx:
--------------------------------------------------------------------------------
1 | import { InfoCircleTwoTone } from '@ant-design/icons';
2 | import { Row, Col, Alert } from 'antd';
3 | import { AlertDescription } from './AlertDescription';
4 |
5 | export const NoInterviewsAlert = () => (
6 |
7 |
8 | }
12 | message="There are no planned interviews."
13 | description={}
14 | />
15 |
16 |
17 | );
18 |
--------------------------------------------------------------------------------
/client/src/modules/Interview/Student/index.ts:
--------------------------------------------------------------------------------
1 | export { NoInterviewsAlert } from './components/NoInterviewsAlert';
2 | export { InterviewCard } from './components/InterviewCard';
3 |
--------------------------------------------------------------------------------
/client/src/modules/Interviews/data/index.ts:
--------------------------------------------------------------------------------
1 | import { FeedbackProps } from './getInterviewData';
2 | import { StageFeedbackProps } from './getStageInterviewData';
3 |
4 | export { getInterviewData, type FeedbackProps } from './getInterviewData';
5 | export { getStageInterviewData, type StageFeedbackProps } from './getStageInterviewData';
6 |
7 | export type PageProps = FeedbackProps | StageFeedbackProps;
8 |
--------------------------------------------------------------------------------
/client/src/modules/Interviews/pages/StageInterviewFeedback/index.ts:
--------------------------------------------------------------------------------
1 | export { StageInterviewFeedback } from './StageInterviewFeedback';
2 |
--------------------------------------------------------------------------------
/client/src/modules/Mentor/components/Instructions/index.tsx:
--------------------------------------------------------------------------------
1 | export { default as Instructions } from './Instructions';
2 | export * from './constants';
3 | export * from './renderers';
4 |
--------------------------------------------------------------------------------
/client/src/modules/Mentor/components/MentorDashboard/index.tsx:
--------------------------------------------------------------------------------
1 | export { default as MentorDashboard } from './MentorDashboard';
2 |
--------------------------------------------------------------------------------
/client/src/modules/Mentor/components/Notification/index.tsx:
--------------------------------------------------------------------------------
1 | export { default as Notification } from './Notification';
2 |
--------------------------------------------------------------------------------
/client/src/modules/Mentor/components/ReviewRandomTask/index.tsx:
--------------------------------------------------------------------------------
1 | export { default as ReviewRandomTask } from './ReviewRandomTask';
2 |
--------------------------------------------------------------------------------
/client/src/modules/Mentor/components/SubmitReviewModal/index.tsx:
--------------------------------------------------------------------------------
1 | export { default as SubmitReviewModal, type SubmitReviewModalProps, MODAL_TITLE } from './SubmitReviewModal';
2 |
--------------------------------------------------------------------------------
/client/src/modules/Mentor/components/TaskSolutionsTable/index.tsx:
--------------------------------------------------------------------------------
1 | export { default as TaskSolutionsTable, type TaskSolutionsTableProps } from './TaskSolutionsTable';
2 | export * from './renderers';
3 |
--------------------------------------------------------------------------------
/client/src/modules/Mentor/components/TaskStatusTabs/index.ts:
--------------------------------------------------------------------------------
1 | export { default as TaskStatusTabs, type Status } from './TaskStatusTabs';
2 |
--------------------------------------------------------------------------------
/client/src/modules/Mentor/components/index.tsx:
--------------------------------------------------------------------------------
1 | export { MentorDashboard } from './MentorDashboard';
2 | export { Notification } from './Notification';
3 | export { Instructions } from './Instructions';
4 | export { TaskSolutionsTable } from './TaskSolutionsTable';
5 | export { SubmitReviewModal } from './SubmitReviewModal';
6 |
--------------------------------------------------------------------------------
/client/src/modules/Mentor/hooks/useMentorDashboard.tsx:
--------------------------------------------------------------------------------
1 | import { useRequest } from 'ahooks';
2 | import { MentorsApi } from 'api';
3 |
4 | const service = new MentorsApi();
5 |
6 | export function useMentorDashboard(mentorId: number | undefined, courseId: number) {
7 | const { data, loading, run } = useRequest(async () => {
8 | if (!mentorId) {
9 | return [];
10 | }
11 | const { data = [] } = await service.getMentorDashboardData(mentorId, courseId);
12 | return data;
13 | });
14 | return [data, loading, run] as const;
15 | }
16 |
--------------------------------------------------------------------------------
/client/src/modules/Mentor/pages/Interviews/hooks/useAlert.ts:
--------------------------------------------------------------------------------
1 | import { useCallback } from 'react';
2 | import { useSessionStorage } from 'react-use';
3 |
4 | export function useAlert(key: string) {
5 | const [isDismissed, setIsDismissed] = useSessionStorage(key, false);
6 |
7 | const setDismissed = useCallback(() => setIsDismissed(true), [setIsDismissed]);
8 |
9 | return [isDismissed, setDismissed] as const;
10 | }
11 |
--------------------------------------------------------------------------------
/client/src/modules/MentorRegistry/index.ts:
--------------------------------------------------------------------------------
1 | export * from './components/MentorRegistryTable';
2 | export * from './components/MentorRegistryTableContainer';
3 | export * from './components/MentorRegistryDeleteModal';
4 | export * from './components/MentorRegistryResendModal';
5 | export * from './constants';
6 |
--------------------------------------------------------------------------------
/client/src/modules/MentorTasksReview/components/AssignReviewerModal/index.ts:
--------------------------------------------------------------------------------
1 | export { default } from './AssignReviewerModal';
2 |
--------------------------------------------------------------------------------
/client/src/modules/MentorTasksReview/pages/MentorTasksReview.constants.ts:
--------------------------------------------------------------------------------
1 | export const sortDirectionMap = {
2 | ascend: 'ASC',
3 | descend: 'DESC',
4 | };
5 |
--------------------------------------------------------------------------------
/client/src/modules/NotAccess/index.ts:
--------------------------------------------------------------------------------
1 | export { default as NotAccess } from './NotAccess';
2 |
--------------------------------------------------------------------------------
/client/src/modules/Opportunities/components/AvatarCv/index.tsx:
--------------------------------------------------------------------------------
1 | import { Avatar } from 'antd';
2 | import { UserOutlined } from '@ant-design/icons';
3 |
4 | type Props = {
5 | src: string | null;
6 | };
7 |
8 | const AVATAR_SIZE = 80;
9 |
10 | export const AvatarCv = (props: Props) => {
11 | const src = props.src ?? undefined;
12 | const icon = src ? null : ;
13 | return ;
14 | };
15 |
--------------------------------------------------------------------------------
/client/src/modules/Opportunities/components/Link/index.tsx:
--------------------------------------------------------------------------------
1 | type Props = {
2 | url: string;
3 | title?: string;
4 | text?: string;
5 | };
6 |
7 | export const Link = ({ url, text, title }: Props) => {
8 | return (
9 |
10 | {text}
11 |
12 | );
13 | };
14 |
--------------------------------------------------------------------------------
/client/src/modules/Opportunities/components/SidebarSectionHeader/index.test.tsx:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import { SidebarSectionHeader } from './index';
3 |
4 | const mockTitle = 'Some title';
5 |
6 | describe('SidebarSectionHeader', () => {
7 | test('should render title', () => {
8 | render();
9 |
10 | const title = screen.getByText(mockTitle);
11 |
12 | expect(title).toBeInTheDocument();
13 | });
14 | });
15 |
--------------------------------------------------------------------------------
/client/src/modules/Opportunities/components/ViewCv/ContactsSection/index.tsx:
--------------------------------------------------------------------------------
1 | import { Contacts } from 'modules/Opportunities/models';
2 | import { ContactsList } from './ContactsList';
3 |
4 | type Props = {
5 | contacts: Contacts | null;
6 | };
7 |
8 | export const ContactsSection = ({ contacts }: Props) => {
9 | if (contacts == null) {
10 | return null;
11 | }
12 |
13 | return (
14 |
15 |
16 |
17 | );
18 | };
19 |
--------------------------------------------------------------------------------
/client/src/modules/Opportunities/components/ViewCv/DataTextValue/index.test.tsx:
--------------------------------------------------------------------------------
1 | import { render, screen } from '@testing-library/react';
2 | import { DataTextValue } from './index';
3 |
4 | const MockContent = () => Mock content
;
5 |
6 | describe('DataTextValue', () => {
7 | test('should display content', () => {
8 | render(
9 |
10 |
11 | ,
12 | );
13 | const mockContent = screen.getByText(/mock content/i);
14 | expect(mockContent).toBeInTheDocument();
15 | });
16 | });
17 |
--------------------------------------------------------------------------------
/client/src/modules/Opportunities/components/ViewCv/DataTextValue/index.tsx:
--------------------------------------------------------------------------------
1 | import { PropsWithChildren } from 'react';
2 | import css from 'styled-jsx/css';
3 |
4 | export const DataTextValue = ({ children }: PropsWithChildren) => {
5 | return (
6 | <>
7 | {children}
8 |
9 | >
10 | );
11 | };
12 |
13 | const styles = css`
14 | .course-data-key {
15 | font-size: 14px;
16 | padding-right: 8px;
17 | white-space: nowrap;
18 | width: 80px;
19 | display: inline-block;
20 | }
21 | `;
22 |
--------------------------------------------------------------------------------
/client/src/modules/Opportunities/constants.ts:
--------------------------------------------------------------------------------
1 | export const enum ExpirationState {
2 | Expired,
3 | NearlyExpired,
4 | NotExpired,
5 | }
6 |
--------------------------------------------------------------------------------
/client/src/modules/Opportunities/data/getContactsToRender.ts:
--------------------------------------------------------------------------------
1 | import { Contacts } from '../models';
2 |
3 | type EntryOf = { [K in keyof T]: [K, T[K]] }[keyof T];
4 |
5 | export const getContactsToRender = (contacts: Contacts | null) => {
6 | if (!contacts) {
7 | return [];
8 | }
9 | const contactsEntries = Object.entries(contacts);
10 | return contactsEntries.filter((contact): contact is EntryOf => contact[1] !== null);
11 | };
12 |
--------------------------------------------------------------------------------
/client/src/modules/Opportunities/hooks/index.ts:
--------------------------------------------------------------------------------
1 | export { useExpiration } from './useExpiration';
2 | export { useResumeData } from './useResumeData';
3 | export { useViewData } from './useViewData';
4 |
--------------------------------------------------------------------------------
/client/src/modules/Opportunities/transformers/index.ts:
--------------------------------------------------------------------------------
1 | export { splitDataForForms } from './splitDataForForms';
2 | export { transformFieldsData } from './transformFieldsData';
3 | export { transformInitialCvData } from './transformInitialCvData';
4 |
--------------------------------------------------------------------------------
/client/src/modules/Profile/components/MentorEndorsement/index.tsx:
--------------------------------------------------------------------------------
1 | export { MentorEndorsement } from './MentorEndorsement';
2 |
--------------------------------------------------------------------------------
/client/src/modules/Registry/components/FormCard/FormCard.tsx:
--------------------------------------------------------------------------------
1 | import { Card } from 'antd';
2 | import { ReactNode } from 'react';
3 |
4 | type Props = {
5 | title: ReactNode;
6 | children?: ReactNode;
7 | };
8 |
9 | export function FormCard({ title, children }: Props) {
10 | return (
11 |
12 | {children}
13 |
14 | );
15 | }
16 |
--------------------------------------------------------------------------------
/client/src/modules/Registry/components/Header/Header.tsx:
--------------------------------------------------------------------------------
1 | import { Space, Typography } from 'antd';
2 | import { ReactNode } from 'react';
3 |
4 | const { Title, Text } = Typography;
5 |
6 | type Props = {
7 | title: ReactNode;
8 | };
9 |
10 | export function Header({ title }: Props) {
11 | return (
12 |
13 | {title}
14 | Free courses from the developer community
15 |
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/client/src/modules/Registry/components/NoCourses/NoCourses.tsx:
--------------------------------------------------------------------------------
1 | import { MehTwoTone } from '@ant-design/icons';
2 | import { Button, Result } from 'antd';
3 |
4 | export function NoCourses() {
5 | return (
6 | }
9 | title="There are no planned courses."
10 | subTitle="Please come back later."
11 | extra={
12 |
15 | }
16 | />
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/client/src/modules/Registry/hooks/index.ts:
--------------------------------------------------------------------------------
1 | export * from './useFormLayout/useFormLayout';
2 | export * from './useMentorData/useMentorData';
3 | export * from './useStudentData/useStudentData';
4 |
--------------------------------------------------------------------------------
/client/src/modules/Registry/hooks/useFormLayout/useFormLayout.ts:
--------------------------------------------------------------------------------
1 | import { Grid } from 'antd';
2 | import { FormLayout } from 'antd/lib/form/Form';
3 |
4 | const { useBreakpoint } = Grid;
5 |
6 | export function useFormLayout() {
7 | const { xs, sm, md, lg, xl, xxl } = useBreakpoint();
8 | const largeScreenSizes = [md, lg, xl, xxl];
9 | const isSmallScreen = xs || (sm && !largeScreenSizes.some(Boolean));
10 | const formLayout: FormLayout = isSmallScreen ? 'vertical' : 'horizontal';
11 |
12 | return { formLayout, isSmallScreen: xs } as const;
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/modules/Registry/pages/index.ts:
--------------------------------------------------------------------------------
1 | export * from './Mentor/Mentor';
2 | export * from './Student/Student';
3 |
--------------------------------------------------------------------------------
/client/src/modules/Schedule/components/AdditionalActions/helpers.ts:
--------------------------------------------------------------------------------
1 | export const buildICalendarLink = (courseId: number, token: string, timezone: string) =>
2 | `/api/v2/courses/${courseId}/icalendar/${token}?timezone=${encodeURIComponent(timezone || '')}`;
3 |
4 | export const buildExportLink = (courseId: number, timezone: string) =>
5 | `/api/course/${courseId}/schedule/csv/${timezone.replace('/', '_')}`;
6 |
7 | export const setExportLink = (link: string) => {
8 | window.location.href = link;
9 | };
10 |
--------------------------------------------------------------------------------
/client/src/modules/Schedule/components/AdditionalActions/index.tsx:
--------------------------------------------------------------------------------
1 | export { default as AdditionalActions } from './AdditionalActions';
2 | export { type AdditionalActionsProps, type MenuItemType } from './AdditionalActions';
3 |
--------------------------------------------------------------------------------
/client/src/modules/Schedule/components/EventDetails/index.ts:
--------------------------------------------------------------------------------
1 | export { EventDetails } from './EventDetails';
2 |
--------------------------------------------------------------------------------
/client/src/modules/Schedule/components/FilteredTags/index.tsx:
--------------------------------------------------------------------------------
1 | import { FilteredTags } from './FilteredTags';
2 |
3 | export default FilteredTags;
4 |
--------------------------------------------------------------------------------
/client/src/modules/Schedule/components/MobileItemCard/index.tsx:
--------------------------------------------------------------------------------
1 | export * from './MobileItemCard';
2 |
--------------------------------------------------------------------------------
/client/src/modules/Schedule/components/SettingsDrawer/index.ts:
--------------------------------------------------------------------------------
1 | export { default as SettingsDrawer } from './SettingsDrawer';
2 |
--------------------------------------------------------------------------------
/client/src/modules/Schedule/components/SettingsPanel/helpers.ts:
--------------------------------------------------------------------------------
1 | import { MenuItemType } from '../AdditionalActions';
2 |
3 | export const buildMenuItem = (title: string, icon: React.ReactNode, isVisible: boolean): MenuItemType | null =>
4 | isVisible
5 | ? {
6 | key: title,
7 | label: title,
8 | icon: icon,
9 | }
10 | : null;
11 |
--------------------------------------------------------------------------------
/client/src/modules/Schedule/components/SettingsPanel/index.ts:
--------------------------------------------------------------------------------
1 | export { default as SettingsPanel } from './SettingsPanel';
2 | export { SettingsButtons, type SettingsPanelProps } from './SettingsPanel';
3 |
--------------------------------------------------------------------------------
/client/src/modules/Schedule/components/StatusTabs/index.ts:
--------------------------------------------------------------------------------
1 | export { default as StatusTabs } from './StatusTabs';
2 |
--------------------------------------------------------------------------------
/client/src/modules/Schedule/components/TableView/index.ts:
--------------------------------------------------------------------------------
1 | export { default as TableView } from './TableView';
2 |
--------------------------------------------------------------------------------
/client/src/modules/Schedule/index.ts:
--------------------------------------------------------------------------------
1 | export { getTaskStatusColor } from './utils';
2 |
--------------------------------------------------------------------------------
/client/src/modules/Score/components/ExportCsvButton/index.tsx:
--------------------------------------------------------------------------------
1 | import { FileExcelOutlined } from '@ant-design/icons';
2 | import { Button } from 'antd';
3 |
4 | type Props = {
5 | enabled?: boolean;
6 | onClick: () => void;
7 | };
8 |
9 | export function ExportCsvButton(props: Props) {
10 | if (!props.enabled) {
11 | return null;
12 | }
13 | return (
14 | } onClick={props.onClick}>
15 | Export CSV
16 |
17 | );
18 | }
19 |
--------------------------------------------------------------------------------
/client/src/modules/Score/data/getExportCsvUrl.ts:
--------------------------------------------------------------------------------
1 | import { getQueryParams, getQueryString } from 'utils/queryParams-utils';
2 |
3 | export function getExportCsvUrl(courseId: number, cityName?: string | string[], mentor?: string | string[]) {
4 | const queryParams = getQueryString(getQueryParams({ cityName, ['mentor.githubId']: mentor }));
5 | const url = buildUrl(courseId, queryParams);
6 | return url;
7 | }
8 |
9 | const buildUrl = (id: number, params: string): string => {
10 | return `/api/course/${id}/students/score/csv${params}`;
11 | };
12 |
--------------------------------------------------------------------------------
/client/src/modules/Score/hooks/types.ts:
--------------------------------------------------------------------------------
1 | export type ScoreTableFilters = {
2 | githubId?: string[];
3 | name?: string[];
4 | 'mentor.githubId'?: string[];
5 | cityName?: string[];
6 | activeOnly: boolean;
7 | };
8 |
9 | export type ScoreOrderField =
10 | | 'rank'
11 | | 'totalScore'
12 | | 'crossCheckScore'
13 | | 'githubId'
14 | | 'name'
15 | | 'cityName'
16 | | 'mentor'
17 | | 'totalScoreChangeDate'
18 | | 'repositoryLastActivityDate';
19 |
20 | export type ScoreOrder = {
21 | field: ScoreOrderField;
22 | order: 'ascend' | 'descend';
23 | column?: { sorter: ScoreOrderField };
24 | };
25 |
--------------------------------------------------------------------------------
/client/src/modules/StudentDashboard/components/AvailableReviewCard/index.ts:
--------------------------------------------------------------------------------
1 | export * from './AvailableReviewCard';
2 |
--------------------------------------------------------------------------------
/client/src/modules/StudentDashboard/components/MentorCard/index.tsx:
--------------------------------------------------------------------------------
1 | export * from './MentorCard';
2 |
--------------------------------------------------------------------------------
/client/src/modules/StudentDashboard/components/MentorInfo/index.ts:
--------------------------------------------------------------------------------
1 | export { default as MentorInfo, type MentorContact } from './MentorInfo';
2 |
--------------------------------------------------------------------------------
/client/src/modules/StudentDashboard/components/NextEventCard/index.tsx:
--------------------------------------------------------------------------------
1 | export { default as NextEventCard } from './NextEventCard';
2 | export * from './renderers';
3 |
--------------------------------------------------------------------------------
/client/src/modules/StudentDashboard/components/SubmitTaskSolution/index.ts:
--------------------------------------------------------------------------------
1 | export { default as SubmitTaskSolution } from './SubmitTaskSolution';
2 |
--------------------------------------------------------------------------------
/client/src/modules/StudentDashboard/components/index.ts:
--------------------------------------------------------------------------------
1 | export * from './CommonDashboardCard';
2 | export * from './MentorCard';
3 | export * from './MainStatsCard';
4 | export * from './TasksStatsCard';
5 | export * from './TasksStatsModal';
6 | export * from './NextEventCard';
7 | export * from './NextEventCard/renderers';
8 | export * from './RepositoryCard';
9 | export * from './AvailableReviewCard';
10 |
--------------------------------------------------------------------------------
/client/src/modules/StudentDashboard/index.ts:
--------------------------------------------------------------------------------
1 | export * from './hooks/useDashboardData';
2 | export * from './hooks/useSubmitTaskSolution';
3 | export * from './components';
4 |
--------------------------------------------------------------------------------
/client/src/modules/Tasks/components/index.ts:
--------------------------------------------------------------------------------
1 | export * from './TasksTable/TasksTable';
2 | export * from './TaskModal/TaskModal';
3 | export * from './TaskSettings/TaskSettings';
4 | export * from './CrossCheckTaskCriteriaPanel/CrossCheckTaskCriteriaPanel';
5 | export * from './GitHubPanel/GitHubPanel';
6 | export * from './JsonAttributesPanel/JsonAttributesPanel';
7 |
--------------------------------------------------------------------------------
/client/src/modules/Tasks/pages/index.ts:
--------------------------------------------------------------------------------
1 | export * from './TasksPage/TasksPage';
2 |
--------------------------------------------------------------------------------
/client/src/modules/TeamDistribution/components/SubmitScoreModal/index.tsx:
--------------------------------------------------------------------------------
1 | export { default as SubmitScoreModal } from './SubmitScoreModal';
2 |
--------------------------------------------------------------------------------
/client/src/modules/TeamDistribution/components/TeamDistributionCard/index.ts:
--------------------------------------------------------------------------------
1 | export { default as TeamDistributionCard } from './TeamDistributionCard';
2 |
--------------------------------------------------------------------------------
/client/src/modules/TeamDistribution/components/TeamDistributionModal/index.ts:
--------------------------------------------------------------------------------
1 | export { default as TeamDistributionModal } from './TeamDistributionModal';
2 |
--------------------------------------------------------------------------------
/client/src/modules/TeamDistribution/components/WelcomeCard/index.ts:
--------------------------------------------------------------------------------
1 | export { default as WelcomeCard } from './WelcomeCard';
2 |
--------------------------------------------------------------------------------
/client/src/modules/TeamDistribution/pages/TeamDistributions/index.tsx:
--------------------------------------------------------------------------------
1 | export { default as TeamDistributions } from './TeamDistributions';
2 |
--------------------------------------------------------------------------------
/client/src/modules/Teams/components/index.ts:
--------------------------------------------------------------------------------
1 | export { default as TeamsHeader } from './TeamsHeader/TeamsHeader';
2 | export { default as TeamModal } from './TeamModal/TeamModal';
3 | export { default as JoinTeamModal } from './JoinTeamModal/JoinTeamModal';
4 | export { default as TeamsSection } from './TeamsSection/TeamsSection';
5 | export { default as StudentsTable } from './StudentsTable/StudentsTable';
6 | export { default as StudentsWithoutTeamSection } from './StudentsWithoutTeamSection/StudentsWithoutTeamSection';
7 | export { default as MyTeamSection } from './MyTeamSection/MyTeamSection';
8 |
--------------------------------------------------------------------------------
/client/src/modules/Teams/hooks/index.ts:
--------------------------------------------------------------------------------
1 | export { useDistribution } from './useDistribution/useDistribution';
2 |
--------------------------------------------------------------------------------
/client/src/modules/Teams/index.tsx:
--------------------------------------------------------------------------------
1 | export { default as Teams } from './Pages/Teams';
2 |
--------------------------------------------------------------------------------
/client/src/pages/admin/contributors.tsx:
--------------------------------------------------------------------------------
1 | import { ContributorPage } from 'modules/Contributor/pages/ContributorPage';
2 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
3 |
4 | export default function () {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/client/src/pages/admin/disciplines.tsx:
--------------------------------------------------------------------------------
1 | import { DisciplinePage } from 'modules/Discipline/pages/DisciplinePage';
2 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
3 |
4 | export default function () {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/client/src/pages/admin/notifications.tsx:
--------------------------------------------------------------------------------
1 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
2 | import { AdminPage } from 'modules/Notifications/pages/AdminNotificationsPage';
3 |
4 | export default function () {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/client/src/pages/admin/prompts.tsx:
--------------------------------------------------------------------------------
1 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
2 | import { PromptsPage } from 'modules/Prompts/pages/PromptPage';
3 |
4 | export default function () {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/client/src/pages/admin/students.tsx:
--------------------------------------------------------------------------------
1 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
2 | import { Students } from 'modules/Students/Pages/Students';
3 |
4 | export default function () {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/client/src/pages/admin/tasks.tsx:
--------------------------------------------------------------------------------
1 | import { CourseRole } from 'services/models';
2 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
3 | import { TasksPage } from 'modules/Tasks/pages';
4 |
5 | export default function () {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/pages/course/403.tsx:
--------------------------------------------------------------------------------
1 | import { CouseNoAccessPage } from 'modules/Course/pages/CouseNoAccess';
2 |
3 | export default CouseNoAccessPage;
4 |
--------------------------------------------------------------------------------
/client/src/pages/course/admin/certified-students.tsx:
--------------------------------------------------------------------------------
1 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
2 | import { CourseRole } from 'services/models';
3 |
4 | export default function () {
5 | return (
6 |
7 | Certified Students
8 |
9 | );
10 | }
11 |
--------------------------------------------------------------------------------
/client/src/pages/course/admin/cross-check-table.tsx:
--------------------------------------------------------------------------------
1 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
2 | import { CrossCheckPairs } from 'modules/CrossCheckPairs/pages/CrossCheckPairs';
3 | import { CourseRole } from 'services/models';
4 |
5 | export default function () {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/pages/course/admin/mentor-tasks-review.tsx:
--------------------------------------------------------------------------------
1 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
2 | import { MentorTasksReview } from 'modules/MentorTasksReview/pages/MentorTasksReview';
3 | import { CourseRole } from 'services/models';
4 |
5 | export default function () {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/pages/course/mentor/dashboard.tsx:
--------------------------------------------------------------------------------
1 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
2 | import { MentorDashboard } from 'modules/Mentor/components';
3 | import { CourseRole } from 'services/models';
4 |
5 | export default function () {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/pages/course/mentor/feedback/index.tsx:
--------------------------------------------------------------------------------
1 | import { CourseRole } from 'services/models';
2 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
3 | import { StudentFeedback } from 'modules/Mentor/pages/StudentFeedback';
4 |
5 | export default function () {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/pages/course/mentor/interview-wait-list.tsx:
--------------------------------------------------------------------------------
1 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
2 | import { InterviewWaitingList } from 'modules/Mentor/pages/InterviewWaitingList';
3 | import { CourseRole } from 'services/models';
4 |
5 | function Page() {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
15 | export default Page;
16 |
--------------------------------------------------------------------------------
/client/src/pages/course/mentor/interviews.tsx:
--------------------------------------------------------------------------------
1 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
2 | import { Interviews } from 'modules/Mentor/pages/Interviews';
3 |
4 | export default function () {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/client/src/pages/course/mentor/students.tsx:
--------------------------------------------------------------------------------
1 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
2 | import { Students } from 'modules/Mentor/pages/Students';
3 | import { CourseRole } from 'services/models';
4 |
5 | export default function () {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
--------------------------------------------------------------------------------
/client/src/pages/course/schedule.tsx:
--------------------------------------------------------------------------------
1 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
2 | import { SchedulePage } from 'modules/Schedule/pages/SchedulePage';
3 |
4 | export default function () {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
--------------------------------------------------------------------------------
/client/src/pages/course/score.tsx:
--------------------------------------------------------------------------------
1 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
2 | import { ScorePage } from 'modules/Score/pages/ScorePage';
3 |
4 | function Page() {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
14 | export default Page;
15 |
--------------------------------------------------------------------------------
/client/src/pages/course/stats.tsx:
--------------------------------------------------------------------------------
1 | import { CourseStatistics } from 'modules/CourseStatistics';
2 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
3 |
4 | function Page() {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
14 | export default Page;
15 |
--------------------------------------------------------------------------------
/client/src/pages/course/student/auto-test/index.tsx:
--------------------------------------------------------------------------------
1 | import { AutoTests } from 'modules/AutoTest/pages';
2 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
3 |
4 | function Page() {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
14 | export default Page;
15 |
--------------------------------------------------------------------------------
/client/src/pages/course/student/auto-test/task.tsx:
--------------------------------------------------------------------------------
1 | import { Task } from 'modules/AutoTest/pages';
2 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
3 | import { CourseRole } from 'services/models';
4 |
5 | function Page() {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
15 | export default Page;
16 |
--------------------------------------------------------------------------------
/client/src/pages/course/student/cross-check-submit.tsx:
--------------------------------------------------------------------------------
1 | import { CrossCheckSubmit } from 'modules/Course/pages/Student/CrossCheckSubmit';
2 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
3 | import { CourseRole } from '../../../services/models';
4 |
5 | function Page() {
6 | return (
7 |
8 |
9 |
10 |
11 |
12 | );
13 | }
14 |
15 | export default Page;
16 |
--------------------------------------------------------------------------------
/client/src/pages/course/team-distributions.tsx:
--------------------------------------------------------------------------------
1 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
2 | import { TeamDistributions } from 'modules/TeamDistribution/pages/TeamDistributions';
3 |
4 | function Page() {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
14 | export default Page;
15 |
--------------------------------------------------------------------------------
/client/src/pages/course/teams.tsx:
--------------------------------------------------------------------------------
1 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
2 | import { Teams } from 'modules/Teams';
3 |
4 | export function Page() {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
14 | export default Page;
15 |
--------------------------------------------------------------------------------
/client/src/pages/cv/[uuid].tsx:
--------------------------------------------------------------------------------
1 | import { PublicPage } from 'modules/Opportunities/pages/PublicPage';
2 | import { getServerSideProps } from 'modules/Opportunities/pages/PublicPage/getServerSideProps';
3 |
4 | export { getServerSideProps };
5 |
6 | export default PublicPage;
7 |
--------------------------------------------------------------------------------
/client/src/pages/cv/edit.tsx:
--------------------------------------------------------------------------------
1 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
2 | import { EditPage } from 'modules/Opportunities/pages/EditPage';
3 |
4 | // force the page to render on the server to fix issue with getting githubId from url
5 | export const getServerSideProps = async () => {
6 | return { props: {} };
7 | };
8 |
9 | export default function () {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 | );
17 | }
18 |
--------------------------------------------------------------------------------
/client/src/pages/index.tsx:
--------------------------------------------------------------------------------
1 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
2 | import { HomePage } from 'modules/Home/pages/HomePage';
3 |
4 | function Page() {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
14 | export default Page;
15 |
--------------------------------------------------------------------------------
/client/src/pages/profile/connection-confirmed.tsx:
--------------------------------------------------------------------------------
1 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
2 | import { ConnectionConfirmed } from 'modules/Notifications/pages/ConnectionConfirmedPage';
3 |
4 | function Page() {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
14 | export default Page;
15 |
--------------------------------------------------------------------------------
/client/src/pages/profile/notifications.tsx:
--------------------------------------------------------------------------------
1 | import { ActiveCourseProvider, SessionProvider } from 'modules/Course/contexts';
2 | import { UserNotificationsPage } from 'modules/Notifications/pages/UserNotificationsSettingsPage';
3 |
4 | function Page() {
5 | return (
6 |
7 |
8 |
9 |
10 |
11 | );
12 | }
13 |
14 | export default Page;
15 |
--------------------------------------------------------------------------------
/client/src/reset.d.ts:
--------------------------------------------------------------------------------
1 | import '@total-typescript/ts-reset';
2 |
3 | declare global {
4 | interface URLSearchParams {
5 | append(name: string, value: string | unknown): void;
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/client/src/services/files.ts:
--------------------------------------------------------------------------------
1 | import globalAxios, { AxiosInstance } from 'axios';
2 |
3 | export class FilesService {
4 | private axios: AxiosInstance;
5 |
6 | constructor() {
7 | this.axios = globalAxios.create({ baseURL: `/api` });
8 | }
9 |
10 | async uploadFile(key: string, data: string) {
11 | const result = await this.axios.post(`/file/upload?key=${key}`, JSON.parse(data));
12 | return result.data.data as { s3Key: string };
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/client/src/services/gratitude.ts:
--------------------------------------------------------------------------------
1 | import axios from 'axios';
2 | import { IGratitudeGetResponse, IGratitudeGetRequest } from '@common/interfaces/gratitude';
3 |
4 | export class GratitudeService {
5 | async getGratitude(data?: IGratitudeGetRequest): Promise<{ content: IGratitudeGetResponse[]; count: number }> {
6 | const result = await axios.get(`/api/feedback/gratitude`, { params: data });
7 | return result.data.data;
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/client/src/services/models.ts:
--------------------------------------------------------------------------------
1 | import { Session } from 'components/withSession';
2 | import { StudentBasic as CommonStudentBasic } from '@common/models';
3 | import { ProfileCourseDto, UserGroupDtoRolesEnum as CourseRole } from 'api';
4 |
5 | export type Course = ProfileCourseDto;
6 | export type StudentBasic = CommonStudentBasic;
7 |
8 | export { CourseRole };
9 |
10 | export interface CoursePageProps {
11 | session?: Session;
12 | course: Course;
13 | params?: Record;
14 | }
15 |
16 | export type CourseOnlyPageProps = {
17 | course: Course;
18 | params?: Record;
19 | };
20 |
--------------------------------------------------------------------------------
/client/src/setupJest.ts:
--------------------------------------------------------------------------------
1 | import '@testing-library/jest-dom';
2 | import matchMediaPolyfill from 'mq-polyfill';
3 |
4 | matchMediaPolyfill(window);
5 |
--------------------------------------------------------------------------------
/client/src/utils/onlyDefined.ts:
--------------------------------------------------------------------------------
1 | import pickBy from 'lodash/pickBy';
2 |
3 | export function onlyDefined>(data: T) {
4 | return pickBy(data, val => val !== undefined && val !== '' && val !== null);
5 | }
6 |
--------------------------------------------------------------------------------
/client/src/utils/optionalQueryString.ts:
--------------------------------------------------------------------------------
1 | export function optionalQueryString(value: string | string[] | undefined) {
2 | if (Array.isArray(value)) {
3 | const trimmedElements = value.map(elem => elem.trim()).join(',');
4 | if (trimmedElements !== '') {
5 | return trimmedElements;
6 | }
7 | } else if (typeof value === 'string') {
8 | return String(value).trim();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/client/src/utils/text-utils.ts:
--------------------------------------------------------------------------------
1 | const githubIdMatch = '[a-z\\d](?:[a-z\\d]|-*(?=[a-z\\d])){0,38}';
2 | const stringStartMatch = '(https?:\\/*\\/)?github.com(\\/)?|https?:\\/*\\/|^';
3 |
4 | const LOGIN_FIND_REGEXP = new RegExp(`(${stringStartMatch})(${githubIdMatch})?`, 'i');
5 |
6 | export const filterLogin = (login: string) => {
7 | const matches = login.trim().match(LOGIN_FIND_REGEXP) || [];
8 | const [foundLogin = ''] = matches.reverse();
9 |
10 | return foundLogin;
11 | };
12 |
--------------------------------------------------------------------------------
/common/enums/mentor/index.ts:
--------------------------------------------------------------------------------
1 | export enum PreferredStudentsLocation {
2 | ANY = 'any',
3 | COUNTRY = 'country',
4 | CITY = 'city',
5 | }
6 |
--------------------------------------------------------------------------------
/common/models/index.ts:
--------------------------------------------------------------------------------
1 | export * from './user';
2 | export * from './stage-interview-feedback';
3 | export * from './profile';
4 | export * from './interview';
5 |
--------------------------------------------------------------------------------
/common/types/pagination/index.ts:
--------------------------------------------------------------------------------
1 | export type IPaginationInfo = {
2 | total?: number;
3 | totalPages?: number;
4 | current: number;
5 | pageSize: number;
6 | };
7 |
--------------------------------------------------------------------------------
/docs/.nojekyll:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/.nojekyll
--------------------------------------------------------------------------------
/docs/CNAME:
--------------------------------------------------------------------------------
1 | docs.app.rs.school
--------------------------------------------------------------------------------
/docs/platform/img/adding-tests-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/adding-tests-1.png
--------------------------------------------------------------------------------
/docs/platform/img/adding-tests-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/adding-tests-2.png
--------------------------------------------------------------------------------
/docs/platform/img/adding-tests-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/adding-tests-3.png
--------------------------------------------------------------------------------
/docs/platform/img/adding-tests-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/adding-tests-4.png
--------------------------------------------------------------------------------
/docs/platform/img/adding-tests-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/adding-tests-5.png
--------------------------------------------------------------------------------
/docs/platform/img/adding-tests-6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/adding-tests-6.png
--------------------------------------------------------------------------------
/docs/platform/img/adding-tests-7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/adding-tests-7.png
--------------------------------------------------------------------------------
/docs/platform/img/adding-tests-8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/adding-tests-8.png
--------------------------------------------------------------------------------
/docs/platform/img/autotest-details.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/autotest-details.jpg
--------------------------------------------------------------------------------
/docs/platform/img/choose-kata-languages/task-json.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/choose-kata-languages/task-json.JPG
--------------------------------------------------------------------------------
/docs/platform/img/choose-kata-languages/task-settings.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/choose-kata-languages/task-settings.JPG
--------------------------------------------------------------------------------
/docs/platform/img/cross-check-scheduling/course-task-modal.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/cross-check-scheduling/course-task-modal.JPG
--------------------------------------------------------------------------------
/docs/platform/img/cv/applicants-page-link.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/cv/applicants-page-link.JPG
--------------------------------------------------------------------------------
/docs/platform/img/cv/applicants-table.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/cv/applicants-table.JPG
--------------------------------------------------------------------------------
/docs/platform/img/cv/cv-form-filled-1.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/cv/cv-form-filled-1.JPG
--------------------------------------------------------------------------------
/docs/platform/img/cv/cv-form-filled.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/cv/cv-form-filled.JPG
--------------------------------------------------------------------------------
/docs/platform/img/cv/cv-view-filled.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/cv/cv-view-filled.JPG
--------------------------------------------------------------------------------
/docs/platform/img/cv/cv-view-print.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/cv/cv-view-print.JPG
--------------------------------------------------------------------------------
/docs/platform/img/cv/edit-cv-buttons.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/cv/edit-cv-buttons.JPG
--------------------------------------------------------------------------------
/docs/platform/img/cv/employer-page.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/cv/employer-page.JPG
--------------------------------------------------------------------------------
/docs/platform/img/cv/header-dropdown.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/cv/header-dropdown.JPG
--------------------------------------------------------------------------------
/docs/platform/img/cv/no-consent-modal.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/cv/no-consent-modal.JPG
--------------------------------------------------------------------------------
/docs/platform/img/cv/no-consent.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/cv/no-consent.JPG
--------------------------------------------------------------------------------
/docs/platform/img/cv/view-control-buttons.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/cv/view-control-buttons.JPG
--------------------------------------------------------------------------------
/docs/platform/img/cv/view-delete-cv.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/cv/view-delete-cv.JPG
--------------------------------------------------------------------------------
/docs/platform/img/no-access.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/no-access.png
--------------------------------------------------------------------------------
/docs/platform/img/schedule-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/schedule-1.png
--------------------------------------------------------------------------------
/docs/platform/img/schedule-10.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/schedule-10.png
--------------------------------------------------------------------------------
/docs/platform/img/schedule-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/schedule-2.png
--------------------------------------------------------------------------------
/docs/platform/img/schedule-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/schedule-3.png
--------------------------------------------------------------------------------
/docs/platform/img/schedule-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/schedule-4.png
--------------------------------------------------------------------------------
/docs/platform/img/schedule-5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/schedule-5.png
--------------------------------------------------------------------------------
/docs/platform/img/schedule-6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/schedule-6.png
--------------------------------------------------------------------------------
/docs/platform/img/schedule-7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/schedule-7.png
--------------------------------------------------------------------------------
/docs/platform/img/schedule-8.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/schedule-8.png
--------------------------------------------------------------------------------
/docs/platform/img/schedule-9.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/schedule-9.png
--------------------------------------------------------------------------------
/docs/platform/img/tasks-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/docs/platform/img/tasks-1.jpg
--------------------------------------------------------------------------------
/nestjs/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .turbo
3 |
--------------------------------------------------------------------------------
/nestjs/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "all",
3 | "tabWidth": 2,
4 | "semi": true,
5 | "singleQuote": true,
6 | "printWidth": 120,
7 | "arrowParens": "avoid"
8 | }
9 |
--------------------------------------------------------------------------------
/nestjs/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:22-alpine
2 |
3 | EXPOSE 8080
4 |
5 | ENV NODE_ENV production
6 | ENV NODE_PORT 8080
7 | ENV TZ utc
8 | ENV RS_ENV production
9 |
10 | WORKDIR /app
11 |
12 | COPY nestjs/package.json /app/nestjs/
13 | COPY package.json /app
14 | COPY package-lock.json /app
15 |
16 | RUN npm install --production --no-optional
17 |
18 | COPY nestjs/dist /app/nestjs/dist
19 |
20 | CMD [ "node", "/app/nestjs/dist/nestjs/src/main" ]
21 |
--------------------------------------------------------------------------------
/nestjs/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import defaultConfig from '../eslint.config.mjs';
2 | export default defaultConfig;
3 |
--------------------------------------------------------------------------------
/nestjs/jest.config.mjs:
--------------------------------------------------------------------------------
1 | export default {
2 | moduleFileExtensions: ['js', 'json', 'ts'],
3 | rootDir: 'src',
4 | testRegex: ['.*\\.spec\\.ts$', 'test\\.ts'],
5 | transform: {
6 | '^.+\\.(t|j)s$': 'ts-jest',
7 | },
8 | collectCoverageFrom: ['**/*.(t|j)s'],
9 | coverageDirectory: '../coverage',
10 | testEnvironment: 'node',
11 | moduleNameMapper: {
12 | '^@common/(.*)$': '/../../common/$1',
13 | '^@entities(.*)$': '/../../server/src/models/$1',
14 | '^src/(.*)$': '/$1',
15 | },
16 | clearMocks: true,
17 | };
18 |
--------------------------------------------------------------------------------
/nestjs/nest-cli.json:
--------------------------------------------------------------------------------
1 | {
2 | "collection": "@nestjs/schematics",
3 | "sourceRoot": "src",
4 | "entryFile": "nestjs/src/main.js"
5 | }
6 |
--------------------------------------------------------------------------------
/nestjs/openapitools.json:
--------------------------------------------------------------------------------
1 | {
2 | "$schema": "node_modules/@openapitools/openapi-generator-cli/config.schema.json",
3 | "spaces": 2,
4 | "generator-cli": {
5 | "version": "5.4.0"
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/nestjs/src/activity/activity.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { ConfigModule } from 'src/config';
3 | import { UsersModule } from 'src/users';
4 | import { ActivityController } from './activity.controller';
5 |
6 | @Module({
7 | controllers: [ActivityController],
8 | imports: [UsersModule, ConfigModule],
9 | })
10 | export class ActivityModule {}
11 |
--------------------------------------------------------------------------------
/nestjs/src/activity/dto/activity.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsBoolean, IsNumber } from 'class-validator';
3 |
4 | export class ActivityDto {
5 | @ApiProperty()
6 | @IsNumber()
7 | public lastActivityTime: number;
8 |
9 | @ApiProperty()
10 | @IsBoolean()
11 | public isActive: boolean;
12 | }
13 |
--------------------------------------------------------------------------------
/nestjs/src/activity/dto/create-activity.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsBoolean } from 'class-validator';
3 |
4 | export class CreateActivityDto {
5 | @ApiProperty()
6 | @IsBoolean()
7 | public isActive: boolean;
8 | }
9 |
--------------------------------------------------------------------------------
/nestjs/src/alerts/alerts.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { TypeOrmModule } from '@nestjs/typeorm';
3 | import { Alert } from '@entities/alert';
4 | import { AlertsController } from './alerts.controller';
5 | import { AlertsService } from './alerts.service';
6 |
7 | @Module({
8 | imports: [TypeOrmModule.forFeature([Alert])],
9 | controllers: [AlertsController],
10 | providers: [AlertsService],
11 | })
12 | export class AlertsModule {}
13 |
--------------------------------------------------------------------------------
/nestjs/src/alerts/dto/create-alert.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class CreateAlertDto {
4 | @ApiProperty()
5 | type: string;
6 | @ApiProperty()
7 | text: string;
8 | @ApiProperty({ required: false })
9 | enabled?: boolean;
10 | @ApiProperty({ required: false })
11 | courseId?: number;
12 | }
13 |
--------------------------------------------------------------------------------
/nestjs/src/alerts/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './alert.dto';
2 | export * from './create-alert.dto';
3 | export * from './update-alert.dto';
4 |
--------------------------------------------------------------------------------
/nestjs/src/alerts/dto/update-alert.dto.ts:
--------------------------------------------------------------------------------
1 | import { PartialType } from '@nestjs/mapped-types';
2 | import { CreateAlertDto } from './create-alert.dto';
3 |
4 | export class UpdateAlertDto extends PartialType(CreateAlertDto) {}
5 |
--------------------------------------------------------------------------------
/nestjs/src/auth/constants.ts:
--------------------------------------------------------------------------------
1 | export const JWT_COOKIE_NAME = 'auth-token';
2 | export const JWT_TOKEN_EXPIRATION = '2d';
3 |
--------------------------------------------------------------------------------
/nestjs/src/auth/course.guard.ts:
--------------------------------------------------------------------------------
1 | import { CanActivate, ExecutionContext, Injectable } from '@nestjs/common';
2 | import { CurrentRequest } from './auth.service';
3 |
4 | @Injectable()
5 | export class CourseGuard implements CanActivate {
6 | public canActivate(context: ExecutionContext) {
7 | const req = context.getArgs<[CurrentRequest]>()[0];
8 | const { user, params } = req;
9 |
10 | if (user.isAdmin) {
11 | return true;
12 | }
13 |
14 | return Boolean(user.courses[Number(params.courseId)]);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/nestjs/src/auth/default.guard.ts:
--------------------------------------------------------------------------------
1 | import { AuthGuard } from '@nestjs/passport';
2 |
3 | export const DefaultGuard = AuthGuard(['jwt', 'basic']);
4 |
--------------------------------------------------------------------------------
/nestjs/src/auth/dto/auth-connection.dto.ts:
--------------------------------------------------------------------------------
1 | import { NotificationChannelId } from '@entities/notificationChannel';
2 | import { ApiProperty } from '@nestjs/swagger';
3 | import { IsNotEmpty } from 'class-validator';
4 |
5 | export class AuthConnectionDto {
6 | @IsNotEmpty()
7 | @ApiProperty()
8 | channelId: NotificationChannelId;
9 |
10 | @IsNotEmpty()
11 | @ApiProperty()
12 | externalId: string;
13 | }
14 |
--------------------------------------------------------------------------------
/nestjs/src/auth/index.ts:
--------------------------------------------------------------------------------
1 | export * from './role.decorator';
2 | export * from './role.guard';
3 | export * from './default.guard';
4 | export * from './auth-user.model';
5 | export * from './auth.service';
6 | export * from './course.guard';
7 |
--------------------------------------------------------------------------------
/nestjs/src/auth/role.decorator.ts:
--------------------------------------------------------------------------------
1 | import { SetMetadata } from '@nestjs/common';
2 | import { Role, CourseRole } from './auth-user.model';
3 |
4 | export const REQUIRED_ROLES_KEY = 'requiredRoles';
5 |
6 | export const RequiredRoles = (roles: (CourseRole | Role)[], requireCourseMatch = false) =>
7 | SetMetadata(REQUIRED_ROLES_KEY, { roles, requireCourseMatch });
8 |
--------------------------------------------------------------------------------
/nestjs/src/auto-test/auto-test.module.ts:
--------------------------------------------------------------------------------
1 | import { Task } from '@entities/index';
2 | import { Module } from '@nestjs/common';
3 | import { TypeOrmModule } from '@nestjs/typeorm';
4 | import { AutoTestController } from './auto-test.controller';
5 | import { AutoTestService } from './auto-test.service';
6 |
7 | @Module({
8 | imports: [TypeOrmModule.forFeature([Task])],
9 | controllers: [AutoTestController],
10 | providers: [AutoTestService],
11 | })
12 | export class AutoTestModule {}
13 |
--------------------------------------------------------------------------------
/nestjs/src/certificates/dto/save-certificate-dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsNumber, IsDateString, IsString } from 'class-validator';
3 |
4 | export class SaveCertificateDto {
5 | @ApiProperty()
6 | @IsString()
7 | public publicId: string;
8 |
9 | @ApiProperty()
10 | @IsNumber()
11 | public studentId: number;
12 |
13 | @ApiProperty()
14 | @IsString()
15 | s3Bucket: string;
16 |
17 | @ApiProperty()
18 | @IsString()
19 | s3Key: string;
20 |
21 | @ApiProperty()
22 | @IsDateString()
23 | issueDate: string;
24 | }
25 |
--------------------------------------------------------------------------------
/nestjs/src/cloud-api/cloud-api.module.ts:
--------------------------------------------------------------------------------
1 | import { HttpModule } from '@nestjs/axios';
2 | import { Module } from '@nestjs/common';
3 | import { ConfigModule } from '../config';
4 | import { CloudApiService } from './cloud-api.service';
5 |
6 | @Module({
7 | imports: [HttpModule, ConfigModule],
8 | controllers: [],
9 | providers: [CloudApiService],
10 | exports: [CloudApiService],
11 | })
12 | export class CloudApiModule {}
13 |
--------------------------------------------------------------------------------
/nestjs/src/config/config.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { ConfigModule as NestConfigModule } from '@nestjs/config';
3 | import { ConfigService } from './config.service';
4 |
5 | @Module({
6 | imports: [NestConfigModule.forRoot({ isGlobal: true })],
7 | controllers: [],
8 | providers: [ConfigService],
9 | exports: [ConfigService],
10 | })
11 | export class ConfigModule {}
12 |
--------------------------------------------------------------------------------
/nestjs/src/config/index.ts:
--------------------------------------------------------------------------------
1 | export * from './config.service';
2 | export * from './config.module';
3 |
--------------------------------------------------------------------------------
/nestjs/src/constants.ts:
--------------------------------------------------------------------------------
1 | // time in seconds
2 | export const DEFAULT_CACHE_TTL = 60; // 1 minute
3 |
4 | export const ONE_HOUR_CACHE_TTL = 60 * 60; // 1 hour
5 |
--------------------------------------------------------------------------------
/nestjs/src/contributors/contributors.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { TypeOrmModule } from '@nestjs/typeorm';
3 | import { ContributorsController } from './contributors.controller';
4 | import { ContributorsService } from './contributors.service';
5 | import { Contributor } from '@entities/contributor';
6 |
7 | @Module({
8 | imports: [TypeOrmModule.forFeature([Contributor])],
9 | controllers: [ContributorsController],
10 | providers: [ContributorsService],
11 | exports: [ContributorsService],
12 | })
13 | export class ContributorsModule {}
14 |
--------------------------------------------------------------------------------
/nestjs/src/contributors/dto/create-contributor.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsNotEmpty, IsNumber, IsString } from 'class-validator';
3 |
4 | export class CreateContributorDto {
5 | @IsNotEmpty()
6 | @IsString()
7 | @ApiProperty()
8 | description: string;
9 |
10 | @IsNotEmpty()
11 | @IsNumber()
12 | @ApiProperty()
13 | userId: number;
14 | }
15 |
--------------------------------------------------------------------------------
/nestjs/src/contributors/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './create-contributor.dto';
2 | export * from './update-contributor.dto';
3 | export * from './contributor.dto';
4 |
--------------------------------------------------------------------------------
/nestjs/src/contributors/dto/update-contributor.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiPropertyOptional } from '@nestjs/swagger';
2 | import { IsNotEmpty, IsNumber, IsString } from 'class-validator';
3 |
4 | export class UpdateContributorDto {
5 | @IsNotEmpty()
6 | @IsString()
7 | @ApiPropertyOptional()
8 | description?: string;
9 |
10 | @IsNotEmpty()
11 | @IsNumber()
12 | @ApiPropertyOptional()
13 | userId?: number;
14 | }
15 |
--------------------------------------------------------------------------------
/nestjs/src/contributors/index.ts:
--------------------------------------------------------------------------------
1 | export * from './contributors.module';
2 |
--------------------------------------------------------------------------------
/nestjs/src/core/core.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { ConfigModule } from '../config';
3 | import { JwtService } from './jwt/jwt.service';
4 | @Module({
5 | imports: [ConfigModule],
6 | controllers: [],
7 | providers: [JwtService],
8 | exports: [JwtService],
9 | })
10 | export class CoreModule {}
11 |
--------------------------------------------------------------------------------
/nestjs/src/core/decorators/index.ts:
--------------------------------------------------------------------------------
1 | export * from './student-id.decorator';
2 |
--------------------------------------------------------------------------------
/nestjs/src/core/decorators/student-id.decorator.ts:
--------------------------------------------------------------------------------
1 | import { createParamDecorator, ExecutionContext } from '@nestjs/common';
2 |
3 | export const StudentId = createParamDecorator((_: unknown, ctx: ExecutionContext): number => {
4 | const request = ctx.switchToHttp().getRequest();
5 | const courseId = request.params.courseId;
6 | return request.user.courses[courseId]?.studentId;
7 | });
8 |
--------------------------------------------------------------------------------
/nestjs/src/core/dto/id-name.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsString } from 'class-validator';
3 |
4 | export class IdNameDto {
5 | constructor(obj: { name: string; id: number }) {
6 | this.id = obj.id;
7 | this.name = obj.name;
8 | }
9 |
10 | @IsString()
11 | @ApiProperty()
12 | name: string;
13 |
14 | @ApiProperty()
15 | id: number;
16 | }
17 |
--------------------------------------------------------------------------------
/nestjs/src/core/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './person.dto';
2 | export * from './pagination.dto';
3 | export * from './id-name.dto';
4 |
--------------------------------------------------------------------------------
/nestjs/src/core/dto/pagination.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class PaginationDto {
4 | constructor(pageSize: number, current: number, total: number, totalPages: number) {
5 | this.pageSize = pageSize;
6 | this.current = current;
7 | this.total = total;
8 | this.totalPages = totalPages;
9 | }
10 |
11 | @ApiProperty()
12 | public pageSize: number;
13 |
14 | @ApiProperty()
15 | public current: number;
16 |
17 | @ApiProperty()
18 | public total: number;
19 |
20 | @ApiProperty()
21 | public totalPages: number;
22 | }
23 |
--------------------------------------------------------------------------------
/nestjs/src/core/filters/entity-not-found.filter.ts:
--------------------------------------------------------------------------------
1 | import { ArgumentsHost, Catch, ExceptionFilter, NotFoundException } from '@nestjs/common';
2 | import { EntityNotFoundError } from 'typeorm';
3 |
4 | const exception = new NotFoundException();
5 |
6 | @Catch(EntityNotFoundError)
7 | export class EntityNotFoundFilter implements ExceptionFilter {
8 | catch(_: EntityNotFoundError, host: ArgumentsHost): any {
9 | const context = host.switchToHttp();
10 | const response = context.getResponse();
11 | return response.status(404).json(exception.getResponse());
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/nestjs/src/core/filters/index.ts:
--------------------------------------------------------------------------------
1 | export * from './entity-not-found.filter';
2 | export * from './sentry.filter';
3 |
--------------------------------------------------------------------------------
/nestjs/src/core/filters/sentry.filter.ts:
--------------------------------------------------------------------------------
1 | import { ArgumentsHost, Catch } from '@nestjs/common';
2 | import { BaseExceptionFilter } from '@nestjs/core';
3 | import * as Sentry from '@sentry/node';
4 |
5 | @Catch()
6 | export class SentryFilter extends BaseExceptionFilter {
7 | catch(exception: unknown, host: ArgumentsHost) {
8 | Sentry.captureException(exception);
9 | super.catch(exception, host);
10 | }
11 | }
12 |
--------------------------------------------------------------------------------
/nestjs/src/core/middlewares/index.ts:
--------------------------------------------------------------------------------
1 | export * from './logger.middleware';
2 | export * from './no-cache.middleware';
3 |
--------------------------------------------------------------------------------
/nestjs/src/core/middlewares/no-cache.middleware.ts:
--------------------------------------------------------------------------------
1 | import { Injectable, NestMiddleware } from '@nestjs/common';
2 | import { NextFunction, Request, Response } from 'express';
3 |
4 | @Injectable()
5 | export class NoCacheMiddleware implements NestMiddleware {
6 | public use(_: Request, res: Response, next: NextFunction) {
7 | res.setHeader('Cache-Control', 'no-cache');
8 | next();
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/nestjs/src/core/subscribers/course-event.subscriber.ts:
--------------------------------------------------------------------------------
1 | import { CourseEvent } from '@entities/courseEvent';
2 | import { EventSubscriber } from 'typeorm';
3 | import { BaseSubscriber } from './base-subscriber';
4 |
5 | @EventSubscriber()
6 | export class CourseEventSubscriber extends BaseSubscriber {
7 | listenTo() {
8 | return CourseEvent;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/nestjs/src/core/subscribers/course-task.subscriber.ts:
--------------------------------------------------------------------------------
1 | import { CourseTask } from '@entities/courseTask';
2 | import { EventSubscriber } from 'typeorm';
3 | import { BaseSubscriber } from './base-subscriber';
4 |
5 | @EventSubscriber()
6 | export class CourseTaskSubscriber extends BaseSubscriber {
7 | listenTo() {
8 | return CourseTask;
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/nestjs/src/core/validation/index.ts:
--------------------------------------------------------------------------------
1 | export * from './validation.exception';
2 | export * from './validation.filter';
3 |
--------------------------------------------------------------------------------
/nestjs/src/core/validation/validation.exception.ts:
--------------------------------------------------------------------------------
1 | import { BadRequestException } from '@nestjs/common';
2 |
3 | export class ValidationException extends BadRequestException {
4 | constructor(public validationErrors: string[]) {
5 | super();
6 | }
7 | }
8 |
--------------------------------------------------------------------------------
/nestjs/src/courses/course-events/index.ts:
--------------------------------------------------------------------------------
1 | export * from './course-events.service';
2 | export * from './course-events.controller';
3 |
--------------------------------------------------------------------------------
/nestjs/src/courses/course-mentors/dto/search-mentor.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class SearchMentorDto {
4 | constructor({ id, githubId, name }: { id: number; githubId: string; name: string }) {
5 | this.id = id;
6 | this.githubId = githubId;
7 | this.name = name;
8 | }
9 |
10 | @ApiProperty()
11 | id: number;
12 |
13 | @ApiProperty()
14 | githubId: string;
15 |
16 | @ApiProperty()
17 | name: string;
18 | }
19 |
--------------------------------------------------------------------------------
/nestjs/src/courses/course-mentors/index.ts:
--------------------------------------------------------------------------------
1 | export * from './course-mentors.service';
2 | export * from './course-mentors.controller';
3 |
--------------------------------------------------------------------------------
/nestjs/src/courses/course-schedule/dto/course-copy-from.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsNumber } from 'class-validator';
3 |
4 | export class CourseCopyFromDto {
5 | @ApiProperty()
6 | @IsNumber()
7 | copyFromCourseId: number;
8 | }
9 |
--------------------------------------------------------------------------------
/nestjs/src/courses/course-schedule/dto/course-schedule-hash.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsString } from 'class-validator';
3 |
4 | export class CourseScheduleTokenDto {
5 | @ApiProperty()
6 | @IsString()
7 | public token: string;
8 | }
9 |
--------------------------------------------------------------------------------
/nestjs/src/courses/course-schedule/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './course-schedule-item.dto';
2 | export * from './course-schedule-hash.dto';
3 |
--------------------------------------------------------------------------------
/nestjs/src/courses/course-schedule/index.ts:
--------------------------------------------------------------------------------
1 | export * from './course-schedule.service';
2 | export * from './course-schedule.controller';
3 | export * from './course-icalendar.service';
4 | export * from './course-icalendar.controller';
5 |
--------------------------------------------------------------------------------
/nestjs/src/courses/course-students/dto/result.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class ResultDto {
4 | @ApiProperty({ type: Number, required: false })
5 | score?: number;
6 |
7 | @ApiProperty({ type: Number, required: false })
8 | courseTaskId?: number;
9 | }
10 |
--------------------------------------------------------------------------------
/nestjs/src/courses/course-tasks/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './course-task.dto';
2 | export * from './course-task-detailed.dto';
3 |
--------------------------------------------------------------------------------
/nestjs/src/courses/course-tasks/index.ts:
--------------------------------------------------------------------------------
1 | export * from './course-tasks.service';
2 | export * from './course-tasks.controller';
3 |
--------------------------------------------------------------------------------
/nestjs/src/courses/course-users/dto/course-roles.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsBoolean, IsOptional } from 'class-validator';
3 |
4 | export class CourseRolesDto {
5 | @IsOptional()
6 | @IsBoolean()
7 | @ApiProperty()
8 | isManager: boolean;
9 |
10 | @IsOptional()
11 | @IsBoolean()
12 | @ApiProperty()
13 | isSupervisor: boolean;
14 |
15 | @IsOptional()
16 | @IsBoolean()
17 | @ApiProperty()
18 | isDementor: boolean;
19 |
20 | @IsOptional()
21 | @IsBoolean()
22 | @ApiProperty()
23 | isActivist: boolean;
24 | }
25 |
--------------------------------------------------------------------------------
/nestjs/src/courses/course-users/dto/update-user.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsNotEmpty, IsNumber } from 'class-validator';
3 | import { CourseRolesDto } from './course-roles.dto';
4 |
5 | export class UpdateCourseUserDto extends CourseRolesDto {
6 | @IsNotEmpty()
7 | @IsNumber()
8 | @ApiProperty()
9 | userId: number;
10 | }
11 |
--------------------------------------------------------------------------------
/nestjs/src/courses/cross-checks/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './check-tasks-pairs.dto';
2 | export * from './cross-check-feedback.dto';
3 | export * from './cross-check-criteria-data.dto';
4 |
--------------------------------------------------------------------------------
/nestjs/src/courses/cross-checks/index.ts:
--------------------------------------------------------------------------------
1 | export * from './course-cross-checks.controller';
2 | export * from './course-cross-checks.service';
3 |
--------------------------------------------------------------------------------
/nestjs/src/courses/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './course.dto';
2 | export * from './leave-course.dto';
3 | export * from './update-course.dto';
4 | export * from './create-course.dto';
5 | export * from './export-course.dto';
6 |
--------------------------------------------------------------------------------
/nestjs/src/courses/dto/leave-course.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class LeaveCourseRequestDto {
4 | @ApiProperty({ required: false })
5 | comment?: string;
6 | }
7 |
--------------------------------------------------------------------------------
/nestjs/src/courses/dto/used-course.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsString } from 'class-validator';
3 |
4 | export class UsedCourseDto {
5 | constructor(course: { name: string; isActive: boolean }) {
6 | this.isActive = course.isActive;
7 | this.name = course.name;
8 | }
9 |
10 | @IsString()
11 | @ApiProperty()
12 | name: string;
13 |
14 | @ApiProperty()
15 | isActive: boolean;
16 | }
17 |
--------------------------------------------------------------------------------
/nestjs/src/courses/index.ts:
--------------------------------------------------------------------------------
1 | export * from './course-tasks/course-tasks.service';
2 | export * from './courses.controller';
3 |
--------------------------------------------------------------------------------
/nestjs/src/courses/interviews/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './interview.dto';
2 |
--------------------------------------------------------------------------------
/nestjs/src/courses/interviews/index.ts:
--------------------------------------------------------------------------------
1 | export * from './interviews.service';
2 | export * from './interviews.controller';
3 | export * from './interviewFeedback.service';
4 |
--------------------------------------------------------------------------------
/nestjs/src/courses/mentor-reviews/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './mentor-reviews-query.dto';
2 | export * from './mentor-reviews.dto';
3 |
--------------------------------------------------------------------------------
/nestjs/src/courses/mentor-reviews/dto/mentor-review-assign.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsInt } from 'class-validator';
3 |
4 | export class MentorReviewAssignDto {
5 | @ApiProperty()
6 | @IsInt()
7 | courseTaskId: number;
8 |
9 | @ApiProperty()
10 | @IsInt()
11 | mentorId: number;
12 |
13 | @ApiProperty()
14 | @IsInt()
15 | studentId: number;
16 | }
17 |
--------------------------------------------------------------------------------
/nestjs/src/courses/mentor-reviews/index.ts:
--------------------------------------------------------------------------------
1 | export * from './mentor-reviews.controller';
2 | export * from './mentor-reviews.service';
3 |
--------------------------------------------------------------------------------
/nestjs/src/courses/mentors/dto/index.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/nestjs/src/courses/mentors/dto/index.ts
--------------------------------------------------------------------------------
/nestjs/src/courses/mentors/index.ts:
--------------------------------------------------------------------------------
1 | export * from './mentors.service';
2 | export * from './mentors.controller';
3 |
--------------------------------------------------------------------------------
/nestjs/src/courses/score/index.ts:
--------------------------------------------------------------------------------
1 | export * from './score.controller';
2 | export * from './score.service';
3 | export * from './write-score.service';
4 |
--------------------------------------------------------------------------------
/nestjs/src/courses/stats/dto/countries-stats.dto.ts:
--------------------------------------------------------------------------------
1 | import { IsString, IsInt, IsArray, ValidateNested } from 'class-validator';
2 | import { ApiProperty } from '@nestjs/swagger';
3 |
4 | export class CountryStatDto {
5 | @IsString()
6 | @ApiProperty()
7 | public countryName: string;
8 |
9 | @IsInt()
10 | @ApiProperty()
11 | public count: number;
12 | }
13 |
14 | export class CountriesStatsDto {
15 | @IsArray()
16 | @ValidateNested({ each: true })
17 | @ApiProperty({ type: [CountryStatDto] })
18 | public countries: CountryStatDto[];
19 | }
20 |
--------------------------------------------------------------------------------
/nestjs/src/courses/stats/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './course-stats.dto';
2 | export * from './countries-stats.dto';
3 | export * from './course-mentors-stats.dto';
4 | export * from './task-performance-stats.dto';
5 |
--------------------------------------------------------------------------------
/nestjs/src/courses/stats/index.ts:
--------------------------------------------------------------------------------
1 | export * from './course-stats.service';
2 | export * from './course-stats.controller';
3 |
--------------------------------------------------------------------------------
/nestjs/src/courses/students/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './student.dto';
2 | export * from './user-students.dto';
3 | export * from './user-students-query.dto';
4 |
--------------------------------------------------------------------------------
/nestjs/src/courses/students/feedbacks/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './create-student-feedback.dto';
2 | export * from './student-feedback.dto';
3 | export * from './update-student-feedback.dto';
4 |
--------------------------------------------------------------------------------
/nestjs/src/courses/students/feedbacks/index.ts:
--------------------------------------------------------------------------------
1 | export * from './feedbacks.controller';
2 | export * from './feedbacks.service';
3 |
--------------------------------------------------------------------------------
/nestjs/src/courses/students/index.ts:
--------------------------------------------------------------------------------
1 | export * from './students.service';
2 | export * from './students.controller';
3 |
--------------------------------------------------------------------------------
/nestjs/src/courses/task-solutions/dto/create-task-solution.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsNotEmpty, IsUrl } from 'class-validator';
3 |
4 | export class SaveTaskSolutionDto {
5 | @ApiProperty()
6 | @IsNotEmpty()
7 | @IsUrl()
8 | url: string;
9 | }
10 |
--------------------------------------------------------------------------------
/nestjs/src/courses/task-solutions/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './task-solution.dto';
2 | export * from './create-task-solution.dto';
3 |
--------------------------------------------------------------------------------
/nestjs/src/courses/task-solutions/index.ts:
--------------------------------------------------------------------------------
1 | export * from './task-solutions.service';
2 | export * from './task-solutions.controller';
3 |
--------------------------------------------------------------------------------
/nestjs/src/courses/task-verifications/dto/create-task-verification.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiPropertyOptional, ApiResponse } from '@nestjs/swagger';
2 | import { IsNumber, IsOptional } from 'class-validator';
3 |
4 | @ApiResponse({})
5 | export class CreateTaskVerificationDto {
6 | constructor(id?: number) {
7 | this.id = id;
8 | }
9 |
10 | @ApiPropertyOptional()
11 | @IsOptional()
12 | @IsNumber()
13 | readonly id?: number;
14 | }
15 |
--------------------------------------------------------------------------------
/nestjs/src/courses/task-verifications/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './self-education.dto';
2 | export * from './task-verifications-attempts.dto';
3 | export * from './create-task-verification.dto';
4 |
--------------------------------------------------------------------------------
/nestjs/src/courses/tasks/dto/check-tasks-deadline.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsNumber } from 'class-validator';
3 |
4 | export class CheckTasksDeadlineDto {
5 | @ApiProperty()
6 | @IsNumber()
7 | public deadlineInHours: number;
8 | }
9 |
--------------------------------------------------------------------------------
/nestjs/src/courses/team-distribution/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './create-team-distribution.dto';
2 | export * from './create-team.dto';
3 | export * from './join-team.dto';
4 | export * from './team-distribution-student.dto';
5 | export * from './team-distribution.dto';
6 | export * from './team.dto';
7 | export * from './update-team-distribution.dto';
8 | export * from './update-team-dto';
9 |
--------------------------------------------------------------------------------
/nestjs/src/courses/team-distribution/dto/join-team.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsNotEmpty, IsString } from 'class-validator';
3 |
4 | export class JoinTeamDto {
5 | @IsString()
6 | @IsNotEmpty()
7 | @ApiProperty()
8 | public password: string;
9 | }
10 |
--------------------------------------------------------------------------------
/nestjs/src/courses/team-distribution/dto/update-team-distribution.dto.ts:
--------------------------------------------------------------------------------
1 | import { CreateTeamDistributionDto } from './create-team-distribution.dto';
2 |
3 | export class UpdateTeamDistributionDto extends CreateTeamDistributionDto {}
4 |
--------------------------------------------------------------------------------
/nestjs/src/courses/team-distribution/dto/update-team-dto.ts:
--------------------------------------------------------------------------------
1 | import { CreateTeamDto } from './create-team.dto';
2 |
3 | export class UpdateTeamDto extends CreateTeamDto {}
4 |
--------------------------------------------------------------------------------
/nestjs/src/cross-check/cross-check.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { TypeOrmModule } from '@nestjs/typeorm';
3 | import { HttpModule } from '@nestjs/axios';
4 | import { CourseTask } from '@entities/courseTask';
5 | import { ConfigModule } from '../config/config.module';
6 | import { CrossCheckService } from './cross-check.service';
7 |
8 | @Module({
9 | imports: [TypeOrmModule.forFeature([CourseTask]), HttpModule, ConfigModule],
10 | providers: [CrossCheckService],
11 | })
12 | export class CrossCheckModule {}
13 |
--------------------------------------------------------------------------------
/nestjs/src/disciplines/disciplines.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { TypeOrmModule } from '@nestjs/typeorm';
3 | import { Discipline } from '@entities/discipline';
4 | import { DisciplinesController } from './disciplines.controller';
5 | import { DisciplinesService } from './disciplines.service';
6 |
7 | @Module({
8 | imports: [TypeOrmModule.forFeature([Discipline])],
9 | controllers: [DisciplinesController],
10 | providers: [DisciplinesService],
11 | exports: [DisciplinesService],
12 | })
13 | export class DisciplinesModule {}
14 |
--------------------------------------------------------------------------------
/nestjs/src/disciplines/dto/create-discipline.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsNotEmpty, IsString } from 'class-validator';
3 |
4 | export class CreateDisciplineDto {
5 | @IsNotEmpty()
6 | @IsString()
7 | @ApiProperty()
8 | name: string;
9 | }
10 |
--------------------------------------------------------------------------------
/nestjs/src/disciplines/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './create-discipline.dto';
2 | export * from './update-discipline.dto';
3 | export * from './discipline.dto';
4 |
--------------------------------------------------------------------------------
/nestjs/src/disciplines/dto/update-discipline.dto.ts:
--------------------------------------------------------------------------------
1 | import { CreateDisciplineDto } from './create-discipline.dto';
2 |
3 | export class UpdateDisciplineDto extends CreateDisciplineDto {}
4 |
--------------------------------------------------------------------------------
/nestjs/src/disciplines/index.ts:
--------------------------------------------------------------------------------
1 | export * from './disciplines.module';
2 |
--------------------------------------------------------------------------------
/nestjs/src/discord-servers/discord-servers.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { TypeOrmModule } from '@nestjs/typeorm';
3 | import { DiscordServer } from '@entities/discordServer';
4 | import { DiscordServersController } from './discord-servers.controller';
5 | import { DiscordServersService } from './discord-servers.service';
6 |
7 | @Module({
8 | imports: [TypeOrmModule.forFeature([DiscordServer])],
9 | controllers: [DiscordServersController],
10 | providers: [DiscordServersService],
11 | })
12 | export class DiscordServersModule {}
13 |
--------------------------------------------------------------------------------
/nestjs/src/discord-servers/dto/create-discord-server.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsNotEmpty, IsString } from 'class-validator';
3 |
4 | export class CreateDiscordServerDto {
5 | @IsNotEmpty()
6 | @IsString()
7 | @ApiProperty()
8 | name: string;
9 |
10 | @IsNotEmpty()
11 | @IsString()
12 | @ApiProperty()
13 | gratitudeUrl: string;
14 |
15 | @IsNotEmpty()
16 | @IsString()
17 | @ApiProperty()
18 | mentorsChatUrl: string;
19 | }
20 |
--------------------------------------------------------------------------------
/nestjs/src/discord-servers/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './discord-server.dto';
2 | export * from './create-discord-server.dto';
3 | export * from './update-discord-server.dto';
4 |
--------------------------------------------------------------------------------
/nestjs/src/discord-servers/dto/update-discord-server.dto.ts:
--------------------------------------------------------------------------------
1 | import { CreateDiscordServerDto } from './create-discord-server.dto';
2 |
3 | export class UpdateDiscordServerDto extends CreateDiscordServerDto {}
4 |
--------------------------------------------------------------------------------
/nestjs/src/events/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './event.dto';
2 | export * from './create-event.dto';
3 | export * from './update-event.dto';
4 |
--------------------------------------------------------------------------------
/nestjs/src/events/dto/update-event.dto.ts:
--------------------------------------------------------------------------------
1 | import { CreateEventDto } from './create-event.dto';
2 |
3 | export class UpdateEventDto extends CreateEventDto {}
4 |
--------------------------------------------------------------------------------
/nestjs/src/events/events.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { EventsService } from './events.service';
3 | import { EventsController } from './events.controller';
4 | import { TypeOrmModule } from '@nestjs/typeorm';
5 | import { Event } from '@entities/event';
6 |
7 | @Module({
8 | imports: [TypeOrmModule.forFeature([Event])],
9 | controllers: [EventsController],
10 | providers: [EventsService],
11 | })
12 | export class EventsModule {}
13 |
--------------------------------------------------------------------------------
/nestjs/src/gratitudes/dto/country.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsString } from 'class-validator';
3 |
4 | export class CountryDto {
5 | constructor({ countryName }: { countryName: string }) {
6 | this.countryName = countryName;
7 | }
8 |
9 | @ApiProperty({ type: String })
10 | @IsString()
11 | countryName: string;
12 | }
13 |
--------------------------------------------------------------------------------
/nestjs/src/gratitudes/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './create-gratitude.dto';
2 | export * from './gratitude.dto';
3 | export * from './badge.dto';
4 | export * from './heroes-radar-query.dto';
5 |
--------------------------------------------------------------------------------
/nestjs/src/gratitudes/index.ts:
--------------------------------------------------------------------------------
1 | export * from './gratitudes.module';
2 |
--------------------------------------------------------------------------------
/nestjs/src/listeners/index.ts:
--------------------------------------------------------------------------------
1 | export { ListenersModule } from './listeners.module';
2 |
--------------------------------------------------------------------------------
/nestjs/src/listeners/listeners.module.ts:
--------------------------------------------------------------------------------
1 | import { HttpModule } from '@nestjs/axios';
2 | import { Module } from '@nestjs/common';
3 | import { ConfigModule } from '../config';
4 | import { CourseListener } from './course.listener';
5 | import { TypeOrmModule } from '@nestjs/typeorm';
6 | import { Course } from '@entities/course';
7 | import { Discipline } from '@entities/discipline';
8 |
9 | @Module({
10 | imports: [ConfigModule, HttpModule, TypeOrmModule.forFeature([Course, Discipline])],
11 | providers: [CourseListener],
12 | })
13 | export class ListenersModule {}
14 |
--------------------------------------------------------------------------------
/nestjs/src/migrations.ts:
--------------------------------------------------------------------------------
1 | export const migrations: any[] = [];
2 |
--------------------------------------------------------------------------------
/nestjs/src/opportunities/dto/consent.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsBoolean } from 'class-validator';
3 |
4 | export class ConsentDto {
5 | constructor(consent: boolean) {
6 | this.consent = consent;
7 | }
8 |
9 | @ApiProperty()
10 | @IsBoolean()
11 | public consent: boolean;
12 | }
13 |
--------------------------------------------------------------------------------
/nestjs/src/opportunities/dto/give-consent-dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsBoolean, IsNumber } from 'class-validator';
3 |
4 | export class GiveConsentDto {
5 | constructor(consent: boolean, expires: number) {
6 | this.consent = consent;
7 | this.expires = expires;
8 | }
9 |
10 | @ApiProperty()
11 | @IsBoolean()
12 | public consent: boolean;
13 |
14 | @ApiProperty()
15 | @IsNumber()
16 | public expires: number;
17 | }
18 |
--------------------------------------------------------------------------------
/nestjs/src/opportunities/dto/status.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class StatusDto {
4 | constructor(expires: number) {
5 | this.expires = expires;
6 | }
7 |
8 | @ApiProperty()
9 | public expires: number;
10 | }
11 |
--------------------------------------------------------------------------------
/nestjs/src/opportunities/dto/visibility.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 |
3 | export class VisibilityDto {
4 | constructor(isHidden: boolean) {
5 | this.isHidden = isHidden;
6 | }
7 |
8 | @ApiProperty()
9 | public isHidden: boolean;
10 | }
11 |
--------------------------------------------------------------------------------
/nestjs/src/profile/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './profile-course.dto';
2 | export * from './update-user.dto';
3 | export * from './update-profile.dto';
4 |
--------------------------------------------------------------------------------
/nestjs/src/profile/dto/profile-course.dto.ts:
--------------------------------------------------------------------------------
1 | import { Course } from '@entities/course';
2 | import { CourseDto } from '../../courses/dto';
3 |
4 | export class ProfileCourseDto extends CourseDto {
5 | constructor(course: Course) {
6 | super(course);
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/nestjs/src/profile/dto/profile.dto.ts:
--------------------------------------------------------------------------------
1 | import { Resume } from '@entities/resume';
2 | import { ApiProperty } from '@nestjs/swagger';
3 |
4 | export class ProfileDto {
5 | constructor(profile: { resume: Resume | null }) {
6 | this.publicCvUrl = profile.resume?.uuid ? `/cv/${profile.resume.uuid}` : null;
7 | }
8 |
9 | @ApiProperty({ type: String, nullable: true })
10 | public publicCvUrl: string | null;
11 | }
12 |
--------------------------------------------------------------------------------
/nestjs/src/profile/index.ts:
--------------------------------------------------------------------------------
1 | export * from './profile.module';
2 |
--------------------------------------------------------------------------------
/nestjs/src/prompts/dto/create-prompt.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsNumber, IsString } from 'class-validator';
3 |
4 | export class CreatePromptDto {
5 | @IsString()
6 | @ApiProperty()
7 | type: string;
8 |
9 | @IsString()
10 | @ApiProperty()
11 | text: string;
12 |
13 | @IsNumber()
14 | @ApiProperty()
15 | temperature: number;
16 | }
17 |
--------------------------------------------------------------------------------
/nestjs/src/prompts/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './prompt.dto';
2 | export * from './create-prompt.dto';
3 | export * from './update-prompt.dto';
4 |
--------------------------------------------------------------------------------
/nestjs/src/prompts/dto/prompt.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { Prompt } from '@entities/prompt';
3 |
4 | export class PromptDto {
5 | constructor(prompt: Prompt) {
6 | this.id = prompt.id;
7 | this.type = prompt.type;
8 | this.text = prompt.text;
9 | this.temperature = prompt.temperature;
10 | }
11 |
12 | @ApiProperty()
13 | id: number;
14 |
15 | @ApiProperty()
16 | type: string;
17 |
18 | @ApiProperty()
19 | text: string;
20 |
21 | @ApiProperty()
22 | temperature: number;
23 | }
24 |
--------------------------------------------------------------------------------
/nestjs/src/prompts/dto/update-prompt.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsNumber, IsOptional, IsString } from 'class-validator';
3 |
4 | export class UpdatePromptDto {
5 | @IsOptional()
6 | @IsNumber()
7 | @ApiProperty()
8 | temperature?: number;
9 |
10 | @IsOptional()
11 | @IsString()
12 | @ApiProperty()
13 | type?: string;
14 |
15 | @IsOptional()
16 | @IsString()
17 | @ApiProperty()
18 | text?: string;
19 | }
20 |
--------------------------------------------------------------------------------
/nestjs/src/prompts/prompts.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { TypeOrmModule } from '@nestjs/typeorm';
3 | import { PromptsController } from './prompts.controller';
4 | import { PromptsService } from './prompts.service';
5 | import { Prompt } from '@entities/prompt';
6 |
7 | @Module({
8 | imports: [TypeOrmModule.forFeature([Prompt])],
9 | controllers: [PromptsController],
10 | providers: [PromptsService],
11 | })
12 | export class PromptsModule {}
13 |
--------------------------------------------------------------------------------
/nestjs/src/registry/constants.ts:
--------------------------------------------------------------------------------
1 | export const DEFAULT_PAGE_SIZE = 200;
2 | export const DEFAULT_PAGE_NUMBER = 1;
3 |
--------------------------------------------------------------------------------
/nestjs/src/registry/dto/approve-mentor.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsArray } from 'class-validator';
3 |
4 | export class ApproveMentorDto {
5 | @ApiProperty()
6 | @IsArray()
7 | preselectedCourses!: string[];
8 | }
9 |
--------------------------------------------------------------------------------
/nestjs/src/registry/dto/comment-mentor-registry.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsString } from 'class-validator';
3 |
4 | export class CommentMentorRegistryDto {
5 | @IsString()
6 | @ApiProperty({ nullable: true, type: String })
7 | public comment: string;
8 | }
9 |
--------------------------------------------------------------------------------
/nestjs/src/registry/dto/invite-mentors.dto.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsArray, IsBoolean, IsOptional, IsString } from 'class-validator';
3 |
4 | export class InviteMentorsDto {
5 | @ApiProperty()
6 | @IsArray()
7 | disciplines: string[];
8 |
9 | @ApiProperty()
10 | @IsBoolean()
11 | @IsOptional()
12 | isMentor?: boolean;
13 |
14 | @ApiProperty()
15 | @IsString()
16 | text: string;
17 | }
18 |
--------------------------------------------------------------------------------
/nestjs/src/reset.d.ts:
--------------------------------------------------------------------------------
1 | import '@total-typescript/ts-reset';
2 |
--------------------------------------------------------------------------------
/nestjs/src/schedule/dto/check-schedule-changes.ts:
--------------------------------------------------------------------------------
1 | import { ApiProperty } from '@nestjs/swagger';
2 | import { IsNumber, IsOptional } from 'class-validator';
3 |
4 | export class CheckScheduleChangesDto {
5 | @ApiProperty()
6 | @IsNumber()
7 | @IsOptional()
8 | public lastHours?: number;
9 | }
10 |
--------------------------------------------------------------------------------
/nestjs/src/session/session.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { SessionController } from './session.controller';
3 | import { AuthModule } from 'src/auth/auth.module';
4 |
5 | @Module({
6 | imports: [AuthModule],
7 | controllers: [SessionController],
8 | })
9 | export class SessionModule {}
10 |
--------------------------------------------------------------------------------
/nestjs/src/tasks/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './create-task.dto';
2 | export * from './update-task.dto';
3 | export * from './task.dto';
4 |
--------------------------------------------------------------------------------
/nestjs/src/tasks/dto/update-task.dto.ts:
--------------------------------------------------------------------------------
1 | import { CreateTaskDto } from './create-task.dto';
2 |
3 | export class UpdateTaskDto extends CreateTaskDto {}
4 |
--------------------------------------------------------------------------------
/nestjs/src/tasks/tasks-criteria/dto/task-criteria.dto.ts:
--------------------------------------------------------------------------------
1 | import { IsArray, IsNotEmpty } from 'class-validator';
2 | import { ApiProperty } from '@nestjs/swagger';
3 | import { CriteriaDto } from './criteria.dto';
4 |
5 | export class TaskCriteriaDto {
6 | @IsNotEmpty()
7 | @IsArray()
8 | @ApiProperty({ type: [CriteriaDto] })
9 | criteria: CriteriaDto[];
10 | }
11 |
--------------------------------------------------------------------------------
/nestjs/src/tasks/tasks-criteria/index.ts:
--------------------------------------------------------------------------------
1 | export { TasksCriteriaController } from './tasks-criteria.controller';
2 | export { TasksCriteriaService } from './tasks-criteria.service';
3 |
--------------------------------------------------------------------------------
/nestjs/src/user-groups/dto/create-user-group.dto.ts:
--------------------------------------------------------------------------------
1 | import { CourseRole } from '@entities/session';
2 | import { ApiProperty } from '@nestjs/swagger';
3 | import { IsArray, IsNotEmpty, IsString } from 'class-validator';
4 |
5 | export class CreateUserGroupDto {
6 | @IsNotEmpty()
7 | @IsString()
8 | @ApiProperty()
9 | name: string;
10 |
11 | @ApiProperty({ type: [Number] })
12 | @IsArray()
13 | users: number[];
14 |
15 | @ApiProperty({ enum: CourseRole, isArray: true })
16 | @IsArray()
17 | roles: CourseRole[];
18 | }
19 |
--------------------------------------------------------------------------------
/nestjs/src/user-groups/dto/index.ts:
--------------------------------------------------------------------------------
1 | export * from './user-group.dto';
2 | export * from './create-user-group.dto';
3 | export * from './update-user-group.dto';
4 |
--------------------------------------------------------------------------------
/nestjs/src/user-groups/dto/update-user-group.dto.ts:
--------------------------------------------------------------------------------
1 | import { CreateUserGroupDto } from './create-user-group.dto';
2 |
3 | export class UpdateUserGroupDto extends CreateUserGroupDto {}
4 |
--------------------------------------------------------------------------------
/nestjs/src/user-groups/index.ts:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/nestjs/src/user-groups/index.ts
--------------------------------------------------------------------------------
/nestjs/src/user-groups/user-groups.module.ts:
--------------------------------------------------------------------------------
1 | import { UserGroup } from '@entities/userGroup';
2 | import { Module } from '@nestjs/common';
3 | import { TypeOrmModule } from '@nestjs/typeorm';
4 | import { UsersModule } from 'src/users';
5 | import { UserGroupsController } from './user-groups.controller';
6 | import { UserGroupsService } from './user-groups.service';
7 |
8 | @Module({
9 | imports: [TypeOrmModule.forFeature([UserGroup]), UsersModule],
10 | controllers: [UserGroupsController],
11 | providers: [UserGroupsService],
12 | })
13 | export class UserGroupsModule {}
14 |
--------------------------------------------------------------------------------
/nestjs/src/users-notifications/dto/update-notification-user-settings.dto.ts:
--------------------------------------------------------------------------------
1 | import { NotificationChannelId } from '@entities/notificationChannel';
2 | import { ApiProperty } from '@nestjs/swagger';
3 | import { IsBoolean } from 'class-validator';
4 |
5 | export class UpdateNotificationUserSettingsDto {
6 | @ApiProperty()
7 | public notificationId: string;
8 |
9 | @ApiProperty()
10 | @IsBoolean()
11 | public enabled: boolean;
12 |
13 | @ApiProperty()
14 | public channelId: NotificationChannelId;
15 | }
16 |
--------------------------------------------------------------------------------
/nestjs/src/users-notifications/index.ts:
--------------------------------------------------------------------------------
1 | export { UsersNotificationsModule } from './users-notifications.module';
2 | export { UserNotificationsService } from './users.notifications.service';
3 |
--------------------------------------------------------------------------------
/nestjs/src/users/dto/index.ts:
--------------------------------------------------------------------------------
1 | export { UserSearchDto } from './user-search.dto';
2 |
--------------------------------------------------------------------------------
/nestjs/src/users/index.ts:
--------------------------------------------------------------------------------
1 | export * from './users.module';
2 |
--------------------------------------------------------------------------------
/nestjs/src/users/users.module.ts:
--------------------------------------------------------------------------------
1 | import { Module } from '@nestjs/common';
2 | import { UsersService } from './users.service';
3 | import { TypeOrmModule } from '@nestjs/typeorm';
4 | import { User } from '@entities/user';
5 | import { UsersController } from './users.controller';
6 |
7 | @Module({
8 | imports: [TypeOrmModule.forFeature([User])],
9 | providers: [UsersService],
10 | controllers: [UsersController],
11 | exports: [UsersService],
12 | })
13 | export class UsersModule {}
14 |
--------------------------------------------------------------------------------
/nestjs/test/jest-e2e.json:
--------------------------------------------------------------------------------
1 | {
2 | "moduleFileExtensions": ["js", "json", "ts"],
3 | "rootDir": ".",
4 | "testEnvironment": "node",
5 | "testRegex": ".e2e-spec.ts$",
6 | "transform": {
7 | "^.+\\.(t|j)s$": "ts-jest"
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/nestjs/tsconfig.build.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./tsconfig.json",
3 | "exclude": ["node_modules", "test", "dist", "**/*spec.ts"]
4 | }
5 |
--------------------------------------------------------------------------------
/server/.dockerignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .turbo
3 |
--------------------------------------------------------------------------------
/server/.env.example:
--------------------------------------------------------------------------------
1 | TZ=utc
2 |
3 | RSSHCOOL_PG_HOST=localhost
4 | RSSHCOOL_PG_USERNAME=rs_master
5 | RSSHCOOL_PG_PASSWORD=12345678
6 | RSSHCOOL_PG_DATABASE=rs_school
7 |
8 | RSSHCOOL_API_ADMIN_USERNAME=admin
9 | RSSHCOOL_API_ADMIN_PASSWORD=password
10 |
--------------------------------------------------------------------------------
/server/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:20-alpine
2 |
3 | EXPOSE 8080
4 |
5 | ENV NODE_ENV production
6 | ENV NODE_PORT 8080
7 | ENV TZ utc
8 | ENV RS_ENV production
9 |
10 | WORKDIR /app
11 |
12 | COPY server/tsconfig.json /app/server/
13 | COPY server/package.json /app/server/
14 |
15 | COPY package.json /app
16 | COPY package-lock.json /app
17 |
18 | RUN npm install --production --no-optional
19 |
20 | COPY server/public /app/server/public
21 | COPY server/dist /app/server/dist
22 |
23 | CMD [ "node", "/app/server/dist/server/src/index.js" ]
24 |
--------------------------------------------------------------------------------
/server/eslint.config.mjs:
--------------------------------------------------------------------------------
1 | import defaultConfig from '../eslint.config.mjs';
2 |
3 | export default defaultConfig;
4 |
--------------------------------------------------------------------------------
/server/jest.config.mjs:
--------------------------------------------------------------------------------
1 | export default {
2 | globals: {
3 | NODE_ENV: 'test',
4 | },
5 | preset: 'ts-jest',
6 | testEnvironment: 'node',
7 | moduleDirectories: ['node_modules', 'src'],
8 | moduleFileExtensions: ['ts', 'js', 'json'],
9 | transform: {
10 | '^.+\\.(ts|tsx)$': 'ts-jest',
11 | },
12 | testPathIgnorePatterns: ['/node_modules/', '/dist/'],
13 | verbose: true,
14 | };
15 |
--------------------------------------------------------------------------------
/server/src/dataSource.ts:
--------------------------------------------------------------------------------
1 | import 'dotenv/config';
2 |
3 | import { DataSource } from 'typeorm';
4 | import { dataSourceOptions } from './dataSourceOptions';
5 |
6 | export default new DataSource(dataSourceOptions);
7 |
--------------------------------------------------------------------------------
/server/src/index.ts:
--------------------------------------------------------------------------------
1 | import 'reflect-metadata'; // for typeorm
2 | import { App } from './app';
3 |
4 | const app = new App();
5 | app
6 | .pgConnect()
7 | .then(() => app.start(true))
8 | .then(() => app.startBackgroundJobs())
9 | .catch(e => console.error(e));
10 |
--------------------------------------------------------------------------------
/server/src/migrations/1630341383942-TaskResult.ts:
--------------------------------------------------------------------------------
1 | import { MigrationInterface, QueryRunner } from 'typeorm';
2 |
3 | export class TaskResult1630341383942 implements MigrationInterface {
4 | public async up(queryRunner: QueryRunner): Promise {
5 | await queryRunner.query(`
6 | UPDATE "task_result"
7 | SET "lastCheckerId" = CAST("historicalScores"->-1->>'authorId' AS INT)
8 | WHERE CAST("historicalScores"->-1->>'authorId' AS INT) > 0
9 | `);
10 | }
11 |
12 | public async down(_: QueryRunner): Promise {
13 | // do nothing
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/server/src/migrations/1638302439645-CourseMigration.ts:
--------------------------------------------------------------------------------
1 | import { MigrationInterface, QueryRunner } from 'typeorm';
2 |
3 | export class CourseMigration1638302439645 implements MigrationInterface {
4 | name = 'CourseMigration1638302439645';
5 |
6 | public async up(queryRunner: QueryRunner): Promise {
7 | await queryRunner.query(`ALTER TABLE "course" ADD "personalMentoring" boolean NOT NULL DEFAULT true`);
8 | }
9 |
10 | public async down(queryRunner: QueryRunner): Promise {
11 | await queryRunner.query(`ALTER TABLE "course" DROP COLUMN "personalMentoring"`);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/server/src/migrations/1639502600339-Student.ts:
--------------------------------------------------------------------------------
1 | import { MigrationInterface, QueryRunner } from 'typeorm';
2 |
3 | export class Student1639502600339 implements MigrationInterface {
4 | name = 'Student1639502600339';
5 |
6 | public async up(queryRunner: QueryRunner): Promise {
7 | await queryRunner.query(`ALTER TABLE "student" ADD "mentoring" boolean DEFAULT true`);
8 | }
9 |
10 | public async down(queryRunner: QueryRunner): Promise {
11 | await queryRunner.query(`ALTER TABLE "student" DROP COLUMN "mentoring"`);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/server/src/migrations/1642884123347-ResumeSelectCourses.ts:
--------------------------------------------------------------------------------
1 | import { MigrationInterface, QueryRunner } from 'typeorm';
2 |
3 | export class ResumeSelectCourses1642884123347 implements MigrationInterface {
4 | name = 'ResumeSelectCourses1642884123347';
5 |
6 | public async up(queryRunner: QueryRunner): Promise {
7 | await queryRunner.query(`ALTER TABLE "resume" ADD "visibleCourses" integer array NOT NULL DEFAULT '{}'`);
8 | }
9 |
10 | public async down(queryRunner: QueryRunner): Promise {
11 | await queryRunner.query(`ALTER TABLE "resume" DROP COLUMN "visibleCourses"`);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/server/src/migrations/1643481312933-Task.ts:
--------------------------------------------------------------------------------
1 | import { MigrationInterface, QueryRunner } from 'typeorm';
2 |
3 | export class Task1643481312933 implements MigrationInterface {
4 | name = 'Task1643481312933';
5 |
6 | public async up(queryRunner: QueryRunner): Promise {
7 | await queryRunner.query(`ALTER TABLE "task" ADD "skills" text NOT NULL DEFAULT ''`);
8 | }
9 |
10 | public async down(queryRunner: QueryRunner): Promise {
11 | await queryRunner.query(`ALTER TABLE "task" DROP COLUMN "skills"`);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/server/src/migrations/1645364514538-RepositoryEvent.ts:
--------------------------------------------------------------------------------
1 | import { MigrationInterface, QueryRunner } from 'typeorm';
2 |
3 | export class RepositoryEvent1645364514538 implements MigrationInterface {
4 | name = 'RepositoryEvent1645364514538';
5 |
6 | public async up(queryRunner: QueryRunner): Promise {
7 | await queryRunner.query(`ALTER TABLE "repository_event" ADD "userId" integer`);
8 | }
9 |
10 | public async down(queryRunner: QueryRunner): Promise {
11 | await queryRunner.query(`ALTER TABLE "repository_event" DROP COLUMN "userId"`);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/server/src/migrations/1650652882300-DiscordChannel.ts:
--------------------------------------------------------------------------------
1 | import { MigrationInterface, QueryRunner } from 'typeorm';
2 |
3 | export class DiscordChannel1650652882300 implements MigrationInterface {
4 | name = 'DiscordChannel1650652882300';
5 |
6 | public async up(queryRunner: QueryRunner): Promise {
7 | await queryRunner.query(`INSERT INTO "notification_channel" (id) VALUES('discord')`);
8 | }
9 |
10 | public async down(queryRunner: QueryRunner): Promise {
11 | await queryRunner.query(`DELETE FROM "notification_channel" WHERE "id" = 'discord'`);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/server/src/migrations/1652870756742-Resume.ts:
--------------------------------------------------------------------------------
1 | import { MigrationInterface, QueryRunner } from 'typeorm';
2 |
3 | export class Resume1652870756742 implements MigrationInterface {
4 | name = 'Resume1652870756742';
5 |
6 | public async up(queryRunner: QueryRunner): Promise {
7 | await queryRunner.query(`ALTER TABLE "resume" ADD "updatedDate" TIMESTAMP NOT NULL DEFAULT now()`);
8 | }
9 |
10 | public async down(queryRunner: QueryRunner): Promise {
11 | await queryRunner.query(`ALTER TABLE "resume" DROP COLUMN "updatedDate"`);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/server/src/migrations/1664183799115-CourseEvent.ts:
--------------------------------------------------------------------------------
1 | import { MigrationInterface, QueryRunner } from 'typeorm';
2 |
3 | export class CourseEvent1664183799115 implements MigrationInterface {
4 | name = 'CourseEvent1664183799115';
5 |
6 | public async up(queryRunner: QueryRunner): Promise {
7 | await queryRunner.query(`ALTER TABLE "course_event" ADD "endTime" TIMESTAMP WITH TIME ZONE`);
8 | }
9 |
10 | public async down(queryRunner: QueryRunner): Promise {
11 | await queryRunner.query(`ALTER TABLE "course_event" DROP COLUMN "endTime"`);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/server/src/migrations/1666621080327-TaskSolutionResult.ts:
--------------------------------------------------------------------------------
1 | import { MigrationInterface, QueryRunner } from 'typeorm';
2 |
3 | export class TaskSolutionResult1666621080327 implements MigrationInterface {
4 | name = 'TaskSolutionResult1666621080327';
5 |
6 | public async up(queryRunner: QueryRunner): Promise {
7 | await queryRunner.query(`ALTER TABLE "task_solution_result" ADD "messages" json NOT NULL DEFAULT '[]'`);
8 | }
9 |
10 | public async down(queryRunner: QueryRunner): Promise {
11 | await queryRunner.query(`ALTER TABLE "task_solution_result" DROP COLUMN "messages"`);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/server/src/migrations/1671475396333-Tasks.ts:
--------------------------------------------------------------------------------
1 | import { MigrationInterface, QueryRunner } from 'typeorm';
2 |
3 | export class Tasks1671475396333 implements MigrationInterface {
4 | name = 'Tasks1671475396333';
5 |
6 | public async up(queryRunner: QueryRunner): Promise {
7 | await queryRunner.query(`ALTER TABLE "task" ADD "deletedDate" TIMESTAMP`);
8 | }
9 |
10 | public async down(queryRunner: QueryRunner): Promise {
11 | await queryRunner.query(`ALTER TABLE "task" DROP COLUMN "deletedDate"`);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/server/src/migrations/1673090827105-TaskVerification.ts:
--------------------------------------------------------------------------------
1 | import { MigrationInterface, QueryRunner } from 'typeorm';
2 |
3 | export class TaskVerification1673090827105 implements MigrationInterface {
4 | name = 'TaskVerification1673090827105';
5 |
6 | public async up(queryRunner: QueryRunner): Promise {
7 | await queryRunner.query(`ALTER TABLE "task_verification" ADD "answers" json NOT NULL DEFAULT '[]'`);
8 | }
9 |
10 | public async down(queryRunner: QueryRunner): Promise {
11 | await queryRunner.query(`ALTER TABLE "task_verification" DROP COLUMN "answers"`);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/server/src/migrations/1673692838338-User.ts:
--------------------------------------------------------------------------------
1 | import { MigrationInterface, QueryRunner } from 'typeorm';
2 |
3 | export class User1673692838338 implements MigrationInterface {
4 | name = 'User1673692838338';
5 |
6 | public async up(queryRunner: QueryRunner): Promise {
7 | await queryRunner.query(`ALTER TABLE "user" ADD "contactsWhatsApp" character varying`);
8 | }
9 |
10 | public async down(queryRunner: QueryRunner): Promise {
11 | await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "contactsWhatsApp"`);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/server/src/migrations/1675245424426-UserGroup.ts:
--------------------------------------------------------------------------------
1 | import { MigrationInterface, QueryRunner } from 'typeorm';
2 |
3 | export class UserGroup1675245424426 implements MigrationInterface {
4 | name = 'UserGroup1675245424426';
5 |
6 | public async up(queryRunner: QueryRunner): Promise {
7 | await queryRunner.query(`ALTER TABLE "course_user" ADD "isDementor" boolean NOT NULL DEFAULT false`);
8 | }
9 |
10 | public async down(queryRunner: QueryRunner): Promise {
11 | await queryRunner.query(`ALTER TABLE "course_user" DROP COLUMN "isDementor"`);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/server/src/migrations/1676139987317-User.ts:
--------------------------------------------------------------------------------
1 | import { MigrationInterface, QueryRunner } from 'typeorm';
2 |
3 | export class User1676139987317 implements MigrationInterface {
4 | name = 'User1676139987317';
5 |
6 | public async up(queryRunner: QueryRunner): Promise {
7 | await queryRunner.query(`ALTER TABLE "user" ADD "languages" text array NOT NULL DEFAULT '{}'`);
8 | }
9 |
10 | public async down(queryRunner: QueryRunner): Promise {
11 | await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "languages"`);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/server/src/migrations/1691520611773-Temperature.ts:
--------------------------------------------------------------------------------
1 | import { MigrationInterface, QueryRunner } from 'typeorm';
2 |
3 | export class Temperature1691520611773 implements MigrationInterface {
4 | name = 'Temperature1691520611773';
5 |
6 | public async up(queryRunner: QueryRunner): Promise {
7 | await queryRunner.query(`ALTER TABLE "prompt" ADD "temperature" integer NOT NULL`);
8 | }
9 |
10 | public async down(queryRunner: QueryRunner): Promise {
11 | await queryRunner.query(`ALTER TABLE "prompt" DROP COLUMN "temperature"`);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/server/src/migrations/1693930286280-CourseUsersActivist.ts:
--------------------------------------------------------------------------------
1 | import { MigrationInterface, QueryRunner } from 'typeorm';
2 |
3 | export class CourseUsersActivist1693930286280 implements MigrationInterface {
4 | name = 'CourseUsersActivist1693930286280';
5 |
6 | public async up(queryRunner: QueryRunner): Promise {
7 | await queryRunner.query(`ALTER TABLE "course_user" ADD "isActivist" boolean NOT NULL DEFAULT false`);
8 | }
9 |
10 | public async down(queryRunner: QueryRunner): Promise {
11 | await queryRunner.query(`ALTER TABLE "course_user" DROP COLUMN "isActivist"`);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/server/src/migrations/1700391857109-Obfuscation.ts:
--------------------------------------------------------------------------------
1 | import { MigrationInterface, QueryRunner } from 'typeorm';
2 |
3 | export class Obfuscation1700391857109 implements MigrationInterface {
4 | name = 'Obfuscation1700391857109';
5 |
6 | public async up(queryRunner: QueryRunner): Promise {
7 | await queryRunner.query(`ALTER TABLE "user" ADD "obfuscated" boolean NOT NULL DEFAULT false`);
8 | }
9 |
10 | public async down(queryRunner: QueryRunner): Promise {
11 | await queryRunner.query(`ALTER TABLE "user" DROP COLUMN "obfuscated"`);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/server/src/migrations/1712137476312-Course.ts:
--------------------------------------------------------------------------------
1 | import { MigrationInterface, QueryRunner } from 'typeorm';
2 |
3 | export class Course1712137476312 implements MigrationInterface {
4 | name = 'Course1712137476312';
5 |
6 | public async up(queryRunner: QueryRunner): Promise {
7 | await queryRunner.query(`ALTER TABLE "course" ADD "certificateThreshold" integer DEFAULT '70'`);
8 | }
9 |
10 | public async down(queryRunner: QueryRunner): Promise {
11 | await queryRunner.query(`ALTER TABLE "course" DROP COLUMN "certificateThreshold"`);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/server/src/migrations/1730926720293-CourseTask.ts:
--------------------------------------------------------------------------------
1 | import { MigrationInterface, QueryRunner } from 'typeorm';
2 |
3 | export class CourseTask1730926720293 implements MigrationInterface {
4 | name = 'CourseTask1730926720293';
5 |
6 | public async up(queryRunner: QueryRunner): Promise {
7 | await queryRunner.query(`ALTER TABLE "course_task" ADD "studentRegistrationStartDate" TIMESTAMP WITH TIME ZONE`);
8 | }
9 |
10 | public async down(queryRunner: QueryRunner): Promise {
11 | await queryRunner.query(`ALTER TABLE "course_task" DROP COLUMN "studentRegistrationStartDate"`);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/server/src/migrations/1736458672717-Course.ts:
--------------------------------------------------------------------------------
1 | import { MigrationInterface, QueryRunner } from 'typeorm';
2 |
3 | export class Course1736458672717 implements MigrationInterface {
4 | name = 'Course1736458672717';
5 |
6 | public async up(queryRunner: QueryRunner): Promise {
7 | await queryRunner.query(`ALTER TABLE "course" ADD "wearecommunityUrl" character varying`);
8 | }
9 |
10 | public async down(queryRunner: QueryRunner): Promise {
11 | await queryRunner.query(`ALTER TABLE "course" DROP COLUMN "wearecommunityUrl"`);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/server/src/models/courseManager.ts:
--------------------------------------------------------------------------------
1 | import { CreateDateColumn, Entity, ManyToOne, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm';
2 | import { Course } from './course';
3 | import { User } from './user';
4 |
5 | @Entity()
6 | export class CourseManager {
7 | @PrimaryGeneratedColumn() id: number;
8 |
9 | @CreateDateColumn()
10 | createdDate: number;
11 |
12 | @UpdateDateColumn()
13 | updatedDate: number;
14 |
15 | @ManyToOne(_ => Course)
16 | course: Course;
17 |
18 | @ManyToOne(_ => User)
19 | user: User;
20 | }
21 |
--------------------------------------------------------------------------------
/server/src/models/data/available-languages.data.ts:
--------------------------------------------------------------------------------
1 | export enum AvailableLanguages {
2 | EN = 'EN',
3 | ZH = 'ZH',
4 | HI = 'HI',
5 | ES = 'ES',
6 | FR = 'FR',
7 | AR = 'AR',
8 | BN = 'BN',
9 | RU = 'RU',
10 | PT = 'PT',
11 | ID = 'ID',
12 | UR = 'UR',
13 | JA = 'JA',
14 | DE = 'DE',
15 | PA = 'PA',
16 | TE = 'TE',
17 | TR = 'TR',
18 | KO = 'KO',
19 | MR = 'MR',
20 | KY = 'KY',
21 | KK = 'KK',
22 | UZ = 'UZ',
23 | KA = 'KA',
24 | PL = 'PL',
25 | LT = 'LT',
26 | LV = 'LV',
27 | BE = 'BE',
28 | UK = 'UK',
29 | }
30 |
--------------------------------------------------------------------------------
/server/src/models/data/index.ts:
--------------------------------------------------------------------------------
1 | export * from './language-levels.data';
2 | export * from './available-languages.data';
3 |
--------------------------------------------------------------------------------
/server/src/models/data/language-levels.data.ts:
--------------------------------------------------------------------------------
1 | export enum LanguageLevel {
2 | Unkwown = 'unknown',
3 | A0 = 'a0',
4 | A1 = 'a1',
5 | A2 = 'a2',
6 | B1 = 'b1',
7 | B2 = 'b2',
8 | C1 = 'c1',
9 | C2 = 'c2',
10 | }
11 |
--------------------------------------------------------------------------------
/server/src/models/discipline.ts:
--------------------------------------------------------------------------------
1 | import { Column, CreateDateColumn, DeleteDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm';
2 |
3 | @Entity()
4 | export class Discipline {
5 | @PrimaryGeneratedColumn({ name: 'id' })
6 | public id: number;
7 |
8 | @CreateDateColumn({ name: 'created_date' })
9 | public createdDate: string;
10 |
11 | @UpdateDateColumn({ name: 'updated_date' })
12 | public updatedDate: string;
13 |
14 | @DeleteDateColumn({ name: 'deleted_date' })
15 | public deletedDate: string;
16 |
17 | @Column({ name: 'name' })
18 | public name: string;
19 | }
20 |
--------------------------------------------------------------------------------
/server/src/models/notificationChannel.ts:
--------------------------------------------------------------------------------
1 | import { Entity, CreateDateColumn, PrimaryColumn, UpdateDateColumn } from 'typeorm';
2 |
3 | @Entity()
4 | export class NotificationChannel {
5 | @PrimaryColumn()
6 | id: NotificationChannelId;
7 |
8 | @CreateDateColumn()
9 | createdDate: number;
10 |
11 | @UpdateDateColumn()
12 | updatedDate: number;
13 | }
14 |
15 | export type NotificationChannelId = 'telegram' | 'email' | 'discord';
16 |
--------------------------------------------------------------------------------
/server/src/models/prompt.ts:
--------------------------------------------------------------------------------
1 | import { Entity, Column, CreateDateColumn, UpdateDateColumn, PrimaryGeneratedColumn, Unique } from 'typeorm';
2 |
3 | @Entity()
4 | @Unique(['type'])
5 | export class Prompt {
6 | @PrimaryGeneratedColumn()
7 | id: number;
8 |
9 | @CreateDateColumn()
10 | createdDate: number;
11 |
12 | @UpdateDateColumn()
13 | updatedDate: number;
14 |
15 | @Column({ type: 'varchar', length: 256 })
16 | type: string;
17 |
18 | @Column({ type: 'float' })
19 | temperature: number;
20 |
21 | @Column()
22 | text: string;
23 | }
24 |
--------------------------------------------------------------------------------
/server/src/models/userGroup.ts:
--------------------------------------------------------------------------------
1 | import { Entity, Column, CreateDateColumn, UpdateDateColumn, PrimaryGeneratedColumn } from 'typeorm';
2 | import { CourseRole } from './session';
3 |
4 | @Entity()
5 | export class UserGroup {
6 | @PrimaryGeneratedColumn() id: number;
7 |
8 | @CreateDateColumn()
9 | createdDate: number;
10 |
11 | @UpdateDateColumn()
12 | updatedDate: number;
13 |
14 | @Column()
15 | name: string;
16 |
17 | @Column('int', { array: true })
18 | users: number[];
19 |
20 | @Column('text', { array: true })
21 | roles: CourseRole[];
22 | }
23 |
--------------------------------------------------------------------------------
/server/src/reset.d.ts:
--------------------------------------------------------------------------------
1 | import '@total-typescript/ts-reset';
2 |
--------------------------------------------------------------------------------
/server/src/routes/checks/getBadComment.ts:
--------------------------------------------------------------------------------
1 | import { OK } from 'http-status-codes';
2 | import { RouterContext } from '../guards';
3 | import { ILogger } from '../../logger';
4 | import { setResponse } from '../utils';
5 | import { getCheckersWithoutComments } from '../../services/check.service';
6 |
7 | export const getBadComment = (_: ILogger) => async (ctx: RouterContext) => {
8 | const { taskId } = ctx.params;
9 |
10 | const badCheckers = await getCheckersWithoutComments(Number(taskId));
11 |
12 | setResponse(ctx, OK, badCheckers);
13 | };
14 |
--------------------------------------------------------------------------------
/server/src/routes/checks/getMaxScoreCheckers.ts:
--------------------------------------------------------------------------------
1 | import { OK } from 'http-status-codes';
2 | import { RouterContext } from '../guards';
3 | import { ILogger } from '../../logger';
4 | import { setResponse } from '../utils';
5 | import { getCheckersWithMaxScore } from '../../services/check.service';
6 |
7 | export const getMaxScoreCheckers = (_: ILogger) => async (ctx: RouterContext) => {
8 | const { taskId } = ctx.params;
9 |
10 | const badCheckers = await getCheckersWithMaxScore(Number(taskId));
11 |
12 | setResponse(ctx, OK, badCheckers);
13 | };
14 |
--------------------------------------------------------------------------------
/server/src/routes/course/crossCheck/index.ts:
--------------------------------------------------------------------------------
1 | export * from './createCompletion';
2 | export * from './createDistribution';
3 | export * from './createResult';
4 | export * from './createSolution';
5 | export * from './createMessage';
6 | export * from './updateMessage';
7 | export * from './deleteSolution';
8 | export * from './getAssignments';
9 | export * from './getResult';
10 | export * from './getSolution';
11 | export * from './getTaskDetails';
12 |
--------------------------------------------------------------------------------
/server/src/routes/course/score/index.ts:
--------------------------------------------------------------------------------
1 | export * from './createMultipleScores';
2 | export * from './createSingleScore';
3 | export * from './getScoreCsv';
4 | export * from './getScoreByStudent';
5 | export * from './recalculateScore';
6 |
--------------------------------------------------------------------------------
/server/src/routes/course/stageInterview/index.ts:
--------------------------------------------------------------------------------
1 | export { createFeedback } from './createFeedback';
2 | export { createInterview } from './createInterview';
3 | export { createInterviews } from './createInterviews';
4 | export { cancelInterview } from './cancelInterview';
5 | export { getFeedback } from './getFeedback';
6 | export { getInterviewStudent } from './getInterviewStudent';
7 | export { getInterviewerStudents } from './getInterviewerStudents';
8 | export { getInterviews } from './getInterviews';
9 | export { updateInterview } from './updateInterview';
10 |
--------------------------------------------------------------------------------
/server/src/routes/course/tasks/index.ts:
--------------------------------------------------------------------------------
1 | export { createCourseTaskDistribution } from './createCourseTaskDistribution';
2 | export { getCourseTasksDetails } from './getCourseTasksDetails';
3 |
--------------------------------------------------------------------------------
/server/src/routes/file/index.ts:
--------------------------------------------------------------------------------
1 | import Router from '@koa/router';
2 | import { ILogger } from '../../logger';
3 | import { guard } from '../guards';
4 | import { uploadFile } from './upload';
5 |
6 | export function filesRoute(logger: ILogger) {
7 | const router = new Router({ prefix: '/file' });
8 |
9 | router.post('/upload', guard, uploadFile(logger));
10 |
11 | return router;
12 | }
13 |
--------------------------------------------------------------------------------
/server/src/routes/repository/index.ts:
--------------------------------------------------------------------------------
1 | import Router from '@koa/router';
2 | import { ILogger } from '../../logger';
3 | import { basicAuthAws } from '../guards';
4 | import { createRepositoryEvents } from './events';
5 |
6 | export function repositoryRoute(logger: ILogger) {
7 | const router = new Router({ prefix: '/repository' });
8 |
9 | router.post('/events', basicAuthAws, createRepositoryEvents(logger));
10 |
11 | return router;
12 | }
13 |
--------------------------------------------------------------------------------
/server/src/routes/taskVerification/index.ts:
--------------------------------------------------------------------------------
1 | import Router from '@koa/router';
2 | import { ILogger } from '../../logger';
3 | import { TaskVerification } from '../../models';
4 | import { createPostRoute } from '../common';
5 | import { adminGuard } from '../guards';
6 |
7 | export function taskVerification(logger: ILogger) {
8 | const router = new Router({ prefix: '/task-verification' });
9 |
10 | router.post('/', adminGuard, createPostRoute(TaskVerification, logger));
11 |
12 | return router;
13 | }
14 |
--------------------------------------------------------------------------------
/server/src/rules/index.ts:
--------------------------------------------------------------------------------
1 | export * from './name';
2 |
--------------------------------------------------------------------------------
/server/src/rules/name.ts:
--------------------------------------------------------------------------------
1 | export const getFullName = (firstName: string, lastName: string, githubId: string) =>
2 | [firstName, lastName].filter(Boolean).join(' ') || githubId;
3 |
--------------------------------------------------------------------------------
/server/src/rules/types.ts:
--------------------------------------------------------------------------------
1 | export type TaskOwnerCourses = {
2 | id: number;
3 | tasksIds: number[];
4 | };
5 |
6 | export type TaskOwnerRole = {
7 | courses: TaskOwnerCourses[];
8 | };
9 |
--------------------------------------------------------------------------------
/server/src/services/distribution/index.ts:
--------------------------------------------------------------------------------
1 | export * from './crossCheckDistribution.service';
2 | export * from './crossMentorDistribution.service';
3 |
--------------------------------------------------------------------------------
/server/src/services/operationResult.ts:
--------------------------------------------------------------------------------
1 | export interface OperationResult {
2 | status: 'created' | 'updated' | 'deleted' | 'skipped' | 'failed';
3 | value: any;
4 | }
5 |
--------------------------------------------------------------------------------
/server/src/services/score/index.ts:
--------------------------------------------------------------------------------
1 | export * from './score.service';
2 |
--------------------------------------------------------------------------------
/server/src/services/taskVerification.service.ts:
--------------------------------------------------------------------------------
1 | import { TaskVerification } from '../models';
2 | import { getRepository } from 'typeorm';
3 |
4 | export async function cancelPendingTasks() {
5 | return getRepository(TaskVerification)
6 | .createQueryBuilder()
7 | .update()
8 | .set({ status: 'cancelled' })
9 | .where(`"updatedDate" + interval '1 hour' < now()::timestamp AND status = 'pending'`)
10 | .execute();
11 | }
12 |
--------------------------------------------------------------------------------
/server/swaggerDef.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | info: {
3 | title: 'rs.school API',
4 | version: '1.0.0',
5 | description: '',
6 | },
7 | basePath: '/api',
8 | };
9 |
--------------------------------------------------------------------------------
/setup/cdk/App.ts:
--------------------------------------------------------------------------------
1 | import * as cdk from 'aws-cdk-lib';
2 | import { RsSchoolAppStack } from './Stack';
3 |
4 | const app = new cdk.App();
5 |
6 | const feature = app.node.tryGetContext('feature') ?? 'master';
7 | const deployId = app.node.tryGetContext('deployId') ?? new Date().getTime().toString();
8 |
9 | new RsSchoolAppStack(app, `rsschool-app-${feature}`, {
10 | env: { account: '511361162520', region: 'eu-central-1' },
11 | feature,
12 | deployId,
13 | certificateArn: 'arn:aws:acm:us-east-1:511361162520:certificate/07e01035-1bb4-430c-8b82-625565f66bdb',
14 | });
15 |
--------------------------------------------------------------------------------
/setup/cdk/cdk.json:
--------------------------------------------------------------------------------
1 | {
2 | "app": "npx tsx App.ts",
3 | "context": {
4 | "@aws-cdk/aws-apigateway:usagePlanKeyOrderInsensitiveId": true,
5 | "@aws-cdk/core:stackRelativeExports": true,
6 | "@aws-cdk/aws-lambda:recognizeVersionProps": true,
7 | "@aws-cdk/aws-cloudfront:defaultSecurityPolicyTLSv1.2_2021": true,
8 | "@aws-cdk/core:target-partitions": ["aws", "aws-cn"]
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/setup/cdk/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "type": "module",
3 | "name": "cdk",
4 | "dependencies": {
5 | "aws-cdk": "2.1012.0",
6 | "aws-cdk-lib": "2.192.0",
7 | "constructs": "^10",
8 | "tsx": "^4.19.2"
9 | }
10 | }
11 |
--------------------------------------------------------------------------------
/setup/docker-compose.yml:
--------------------------------------------------------------------------------
1 | services:
2 | postgres:
3 | image: postgres:15.5
4 | container_name: db
5 | restart: always
6 | #volumes:
7 | # - /tmp/postgresql:/var/lib/postgresql
8 | environment:
9 | POSTGRES_PASSWORD: 12345678
10 | POSTGRES_USER: rs_master
11 | POSTGRES_DB: rs_school
12 | PGDATA: /tmp
13 | ports:
14 | - 5432:5432
15 |
--------------------------------------------------------------------------------
/setup/dump-local.sh:
--------------------------------------------------------------------------------
1 | pg_dump -h localhost --username rs_master rs_school --file backup-local.sql
--------------------------------------------------------------------------------
/setup/dump.sh:
--------------------------------------------------------------------------------
1 | pg_dump -h $RSSCHOOL_AWS_RDS_HOST --username rs_master rs_school --file backup.sql
2 |
--------------------------------------------------------------------------------
/setup/restore-local.sh:
--------------------------------------------------------------------------------
1 | podman exec -i db psql -U rs_master -d rs_school < ./backup-local.sql
2 |
--------------------------------------------------------------------------------
/setup/restore.sh:
--------------------------------------------------------------------------------
1 | podman exec -i db psql -U rs_master -d rs_school < ./backup.sql
2 |
--------------------------------------------------------------------------------
/tools/bumblebee/.env.example:
--------------------------------------------------------------------------------
1 | RS_BUMBLEBEE_TELEGRAM_TOKEN=
2 | RS_BUMBLEBEE_TELEGRAM_ADMIN_CHANNEL_ID=
3 | RS_BUMBLEBEE_TELEGRAM_CHANNEL_ID=
4 | RS_BUMBLEBEE_DISCORD_TOKEN=
5 | RS_BUMBLEBEE_DISCORD_CHANNEL_NAMES=announcements
6 | RS_BUMBLEBEE_LIMIT_INITIAL_MESSAGES_COUNT=50
7 | RS_BUMBLEBEE_PAUSE_BETWEEN_TELEGRAM_SENDS=2000
8 |
--------------------------------------------------------------------------------
/tools/bumblebee/.gitignore:
--------------------------------------------------------------------------------
1 | timestamp.json
2 |
--------------------------------------------------------------------------------
/tools/bumblebee/Dockerfile:
--------------------------------------------------------------------------------
1 | FROM node:16
2 |
3 | EXPOSE 7000
4 |
5 | ENV NODE_ENV production
6 | ENV NODE_PORT 7000
7 | ENV TZ utc
8 |
9 | WORKDIR /app
10 |
11 | RUN mkdir -p /tmp/timestamp
12 | VOLUME /tmp/timestamp
13 |
14 | COPY package.json /app
15 | COPY package-lock.json /app
16 | RUN npm install --production --no-optional
17 |
18 | COPY src /app/src
19 |
20 | CMD [ "npm", "start" ]
21 |
--------------------------------------------------------------------------------
/tools/bumblebee/README.md:
--------------------------------------------------------------------------------
1 | # rs-bumblebee
2 | RS Bumblebee is a bridge bot for transfer messages from Discord to Telegram created especially for the Rolling Scopes School
3 |
4 | ## Developing
5 | These librares are using for developing:
6 | - [node-telegram-bot-api](https://github.com/yagop/node-telegram-bot-api/blob/master/doc/api.md)
7 | - [discord.js](https://discord.js.org/#/docs/main/stable/general/welcome)
8 |
9 |
--------------------------------------------------------------------------------
/tools/bumblebee/src/constants/defaults.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | LIMIT_INITIAL_MESSAGES_COUNT: 50,
3 | PAUSE_BETWEEN_TELEGRAM_SENDS: 2000,
4 | };
5 |
--------------------------------------------------------------------------------
/tools/bumblebee/src/constants/discord-bridge.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | LOCALE: 'en',
3 | TIMEZONE: 'Europe/Minsk',
4 | TIME_FORMAT: 'llll',
5 | TELEGRAM_PARSE_MODE: 'Markdown',
6 | TIMESTAMP_FILE_NAME: 'timestamp.json',
7 | };
8 |
--------------------------------------------------------------------------------
/tools/bumblebee/src/discord/events/index.js:
--------------------------------------------------------------------------------
1 | const ready = require('./ready');
2 | const message = require('./message');
3 | const messageUpdate = require('./message-update');
4 | const messageDelete = require('./message-delete');
5 |
6 | module.exports = {
7 | ready,
8 | message,
9 | messageUpdate,
10 | messageDelete,
11 | };
12 |
--------------------------------------------------------------------------------
/tools/bumblebee/src/discord/index.js:
--------------------------------------------------------------------------------
1 | const { createClient, listen } = require('./discord-bridge');
2 |
3 | module.exports = async (telegramBot) => {
4 | const client = await createClient();
5 |
6 | listen(client, telegramBot);
7 | };
8 |
--------------------------------------------------------------------------------
/tools/bumblebee/src/index.js:
--------------------------------------------------------------------------------
1 | const dotenv = require('dotenv');
2 | const discord = require('./discord');
3 | const telegram = require('./telegram');
4 |
5 | dotenv.config();
6 |
7 | const telegramBot = telegram();
8 | discord(telegramBot);
9 |
10 | global.console.log(`rs-bumblebee is started!`);
11 |
--------------------------------------------------------------------------------
/tools/bumblebee/src/lib/common.js:
--------------------------------------------------------------------------------
1 | module.exports.catcher = handler => async (...args) => {
2 | try {
3 | const result = handler(...args);
4 | if (result instanceof Promise) {
5 | return await result;
6 | }
7 | return result;
8 | } catch (err) {
9 | return global.console.log('Error =>', err.message);
10 | }
11 | };
12 |
--------------------------------------------------------------------------------
/tools/bumblebee/src/telegram/events/help.js:
--------------------------------------------------------------------------------
1 | module.exports = ({ client }) => ({
2 | description: 'Show this message',
3 | method: ({ chat: { id } }) => {
4 | // eslint-disable-next-line global-require
5 | const events = require('./index');
6 |
7 | const message = Object.keys(events)
8 | .map(eventName => `/${eventName} : ${events[eventName]({ client }).description}`)
9 | .join('\n');
10 |
11 | client.sendMessage(id, message, { parse_mode: 'Markdown' });
12 | },
13 | });
14 |
--------------------------------------------------------------------------------
/tools/bumblebee/src/telegram/events/index.js:
--------------------------------------------------------------------------------
1 | const start = require('./start');
2 | const ping = require('./ping');
3 | const help = require('./help');
4 |
5 | module.exports = {
6 | start,
7 | ping,
8 | help,
9 | };
10 |
--------------------------------------------------------------------------------
/tools/bumblebee/src/telegram/events/ping.js:
--------------------------------------------------------------------------------
1 | module.exports = ({ client }) => ({
2 | description: 'Show status if rs-bumblebee is available',
3 | method: ({ chat: { id } }) => {
4 | const messages = [
5 | 'I\'m here!',
6 | 'Sir, yes, sir!',
7 | 'I am waiting for orders.',
8 | ];
9 |
10 | console.log(id);
11 | const randomIndex = Math.floor(Math.random() * messages.length);
12 |
13 | client.sendMessage(id, messages[randomIndex]);
14 | },
15 | });
16 |
--------------------------------------------------------------------------------
/tools/bumblebee/src/telegram/events/start.js:
--------------------------------------------------------------------------------
1 | module.exports = ({ client }) => ({
2 | description: 'Start rs-bumblebee',
3 | method: ({
4 | from: {
5 | first_name: firstName,
6 | last_name: lastName = '',
7 | },
8 | chat: { id },
9 | }) => {
10 | const message = `Hello *${firstName} ${lastName}*! Glad to see you.\nType /help for available options.`;
11 |
12 | client.sendMessage(id, message, { parse_mode: 'Markdown' });
13 | },
14 | });
15 |
--------------------------------------------------------------------------------
/tools/bumblebee/src/telegram/index.js:
--------------------------------------------------------------------------------
1 | const { createClient, listen } = require('./telegram-bot');
2 |
3 | module.exports = async () => {
4 | const client = await createClient();
5 |
6 | listen(client);
7 |
8 | return client;
9 | };
10 |
--------------------------------------------------------------------------------
/tools/sloths/.env.example:
--------------------------------------------------------------------------------
1 | VITE_CDN_URL=http://localhost:5173/cdn
2 |
--------------------------------------------------------------------------------
/tools/sloths/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "trailingComma": "es5",
3 | "tabWidth": 2,
4 | "semi": true,
5 | "singleQuote": true,
6 | "printWidth": 120
7 | }
--------------------------------------------------------------------------------
/tools/sloths/README.md:
--------------------------------------------------------------------------------
1 | # rs-sloths
2 |
3 | RS SLOTHS is a depository of sloths. View all existing stickers, download the necessary ones or chill a bit - why not? Feel a sloth!
4 |
5 | ## Stack
6 |
7 | Vue3, Pinia, Vue Router, TypeScript, Vite
8 |
9 | ## Project Setup
10 |
11 | ```sh
12 | npm install
13 | ```
14 |
15 | ### Compile and Hot-Reload for Development
16 |
17 | ```sh
18 | npm run dev
19 | ```
20 |
21 | ### Type-Check, Compile and Minify for Production
22 |
23 | ```sh
24 | npm run build
25 | ```
26 |
27 | ### Lint with [ESLint](https://eslint.org/)
28 |
29 | ```sh
30 | npm run lint
31 | ```
32 |
--------------------------------------------------------------------------------
/tools/sloths/env.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 |
--------------------------------------------------------------------------------
/tools/sloths/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | RS-SLOTHS
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/tools/sloths/public/cdn/cleaned/filelist.json:
--------------------------------------------------------------------------------
1 | ["codewars.svg", "congrats.svg", "deadline.svg"]
2 |
--------------------------------------------------------------------------------
/tools/sloths/public/cdn/stickers/activist/metadata.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Activist",
3 | "description": "Primus inter pares",
4 | "tags": ["activist", "hero"]
5 | }
6 |
--------------------------------------------------------------------------------
/tools/sloths/public/cdn/stickers/codewars/metadata.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Codewars",
3 | "description": "Как-то летним днём\nСамурай не сдал кросс-чек!\nГрустно. 0 баллов.",
4 | "tags": ["student", "samurai", "codewars"]
5 | }
6 |
--------------------------------------------------------------------------------
/tools/sloths/public/cdn/stickers/congrats/metadata.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "Congrats",
3 | "description": "Bring on the Champagne!",
4 | "tags": ["congratulations", "student"]
5 | }
6 |
--------------------------------------------------------------------------------
/tools/sloths/public/favicon/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/public/favicon/favicon-32x32.png
--------------------------------------------------------------------------------
/tools/sloths/public/favicon/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/public/favicon/favicon.ico
--------------------------------------------------------------------------------
/tools/sloths/public/img/merch/hoodie.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/public/img/merch/hoodie.png
--------------------------------------------------------------------------------
/tools/sloths/public/img/merch/mug.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/public/img/merch/mug.png
--------------------------------------------------------------------------------
/tools/sloths/public/img/merch/thermo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/public/img/merch/thermo.png
--------------------------------------------------------------------------------
/tools/sloths/public/img/merch/tshirt.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/public/img/merch/tshirt.png
--------------------------------------------------------------------------------
/tools/sloths/public/img/photo/ogimly.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/public/img/photo/ogimly.png
--------------------------------------------------------------------------------
/tools/sloths/public/img/photo/vanet.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/public/img/photo/vanet.png
--------------------------------------------------------------------------------
/tools/sloths/public/img/photo/wiijoy.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/public/img/photo/wiijoy.png
--------------------------------------------------------------------------------
/tools/sloths/public/img/preview.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tools/sloths/src/assets/backgrounds/bg-footer-dark.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/tools/sloths/src/assets/backgrounds/bg-footer-light.svg:
--------------------------------------------------------------------------------
1 |
4 |
--------------------------------------------------------------------------------
/tools/sloths/src/assets/fonts/Arial-Black.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/src/assets/fonts/Arial-Black.woff
--------------------------------------------------------------------------------
/tools/sloths/src/assets/fonts/Arial-Black.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/src/assets/fonts/Arial-Black.woff2
--------------------------------------------------------------------------------
/tools/sloths/src/assets/fonts/NunitoSans-Black.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/src/assets/fonts/NunitoSans-Black.woff
--------------------------------------------------------------------------------
/tools/sloths/src/assets/fonts/NunitoSans-Black.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/src/assets/fonts/NunitoSans-Black.woff2
--------------------------------------------------------------------------------
/tools/sloths/src/assets/fonts/NunitoSans-Bold.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/src/assets/fonts/NunitoSans-Bold.woff
--------------------------------------------------------------------------------
/tools/sloths/src/assets/fonts/NunitoSans-Bold.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/src/assets/fonts/NunitoSans-Bold.woff2
--------------------------------------------------------------------------------
/tools/sloths/src/assets/fonts/NunitoSans-Light.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/src/assets/fonts/NunitoSans-Light.woff
--------------------------------------------------------------------------------
/tools/sloths/src/assets/fonts/NunitoSans-Light.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/src/assets/fonts/NunitoSans-Light.woff2
--------------------------------------------------------------------------------
/tools/sloths/src/assets/fonts/NunitoSans-Regular.woff:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/src/assets/fonts/NunitoSans-Regular.woff
--------------------------------------------------------------------------------
/tools/sloths/src/assets/fonts/NunitoSans-Regular.woff2:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/src/assets/fonts/NunitoSans-Regular.woff2
--------------------------------------------------------------------------------
/tools/sloths/src/assets/icons/btn/center-square-black.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/tools/sloths/src/assets/icons/btn/center-square.svg:
--------------------------------------------------------------------------------
1 |
5 |
--------------------------------------------------------------------------------
/tools/sloths/src/assets/icons/btn/check-circle-fill.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tools/sloths/src/assets/icons/btn/check-circle.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tools/sloths/src/assets/icons/btn/check-square-black.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tools/sloths/src/assets/icons/btn/check-square.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tools/sloths/src/assets/icons/btn/dash-square-black.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tools/sloths/src/assets/icons/btn/dash-square.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tools/sloths/src/assets/icons/btn/download-black.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tools/sloths/src/assets/icons/btn/download.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tools/sloths/src/assets/icons/btn/plus-square-black.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tools/sloths/src/assets/icons/btn/plus-square.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/tools/sloths/src/assets/icons/rs-school.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/src/assets/icons/rs-school.png
--------------------------------------------------------------------------------
/tools/sloths/src/assets/sounds/fail.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/src/assets/sounds/fail.mp3
--------------------------------------------------------------------------------
/tools/sloths/src/assets/sounds/flip.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/src/assets/sounds/flip.mp3
--------------------------------------------------------------------------------
/tools/sloths/src/assets/sounds/ovation.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/src/assets/sounds/ovation.mp3
--------------------------------------------------------------------------------
/tools/sloths/src/assets/sounds/sad-trombone.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/src/assets/sounds/sad-trombone.mp3
--------------------------------------------------------------------------------
/tools/sloths/src/assets/sounds/slide.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/src/assets/sounds/slide.mp3
--------------------------------------------------------------------------------
/tools/sloths/src/assets/sounds/success.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/src/assets/sounds/success.mp3
--------------------------------------------------------------------------------
/tools/sloths/src/assets/sounds/ta-da.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/rolling-scopes/rsschool-app/51294715c03ccd8e6e38b05e33859d28e86bc08e/tools/sloths/src/assets/sounds/ta-da.mp3
--------------------------------------------------------------------------------
/tools/sloths/src/assets/styles/main.css:
--------------------------------------------------------------------------------
1 | @import './fonts.css';
2 | @import './variables.css';
3 |
4 | @import './base.css';
5 |
--------------------------------------------------------------------------------
/tools/sloths/src/i18n.ts:
--------------------------------------------------------------------------------
1 | import { createI18n } from 'vue-i18n';
2 | import en from './assets/locales/en.json';
3 |
4 | const i18n = createI18n({
5 | legacy: false,
6 | locale: 'en',
7 | fallbackLocale: 'en',
8 | messages: {
9 | en,
10 | },
11 | globalInjection: true,
12 | });
13 |
14 | export default i18n;
15 |
--------------------------------------------------------------------------------
/tools/sloths/src/main.ts:
--------------------------------------------------------------------------------
1 | import { createApp } from 'vue';
2 | import { createPinia } from 'pinia';
3 |
4 | import Shortkey from 'vue-three-shortkey';
5 | import i18n from './i18n';
6 | import App from './App.vue';
7 | import router from './router';
8 |
9 | import 'normalize.css/normalize.css';
10 | import './assets/styles/main.css';
11 |
12 | const app = createApp(App);
13 |
14 | app.use(createPinia());
15 | app.use(router);
16 | app.use(i18n);
17 | app.use(Shortkey, { prevent: ['input', 'textarea'] });
18 |
19 | app.mount('#app');
20 |
--------------------------------------------------------------------------------
/tools/sloths/src/services/error-handler.ts:
--------------------------------------------------------------------------------
1 | import useAlertModal from '@/stores/alert-modal';
2 |
3 | const { showAlertModal } = useAlertModal();
4 |
5 | export const errorHandler = (error: unknown) => {
6 | showAlertModal('modal.header.error', `${error}`);
7 | };
8 |
9 | export default errorHandler;
10 |
--------------------------------------------------------------------------------
/tools/sloths/src/shims-vue.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.vue';
2 | declare module 'vue-three-shortkey';
3 |
--------------------------------------------------------------------------------
/tools/sloths/src/stores/alert-modal.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia';
2 |
3 | const useAlertModal = defineStore({
4 | id: 'alertModal',
5 |
6 | state: () => ({
7 | isAlert: false,
8 | header: '',
9 | message: '',
10 | }),
11 |
12 | actions: {
13 | showAlertModal(header: string, message: string) {
14 | this.isAlert = true;
15 | this.header = header;
16 | this.message = message;
17 | },
18 | },
19 | });
20 |
21 | export default useAlertModal;
22 |
--------------------------------------------------------------------------------
/tools/sloths/src/stores/audio-on.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia';
2 |
3 | const useAudioOn = defineStore({
4 | id: 'audioOn',
5 |
6 | state: () => ({
7 | isAudioOn: false,
8 | }),
9 | });
10 |
11 | export default useAudioOn;
12 |
--------------------------------------------------------------------------------
/tools/sloths/src/stores/cleaned.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia';
2 |
3 | const useCleanedStore = defineStore({
4 | id: 'cleaned',
5 | state: () => ({
6 | cleanedFilelist: [] as string[],
7 | originalFilelist: [] as string[],
8 | }),
9 | });
10 |
11 | export default useCleanedStore;
12 |
--------------------------------------------------------------------------------
/tools/sloths/src/stores/counter.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia';
2 |
3 | const useCounterStore = defineStore({
4 | id: 'counter',
5 | state: () => ({
6 | counter: 0,
7 | }),
8 | getters: {
9 | doubleCount: (state) => state.counter * 2,
10 | },
11 | actions: {
12 | increment() {
13 | this.counter += 1;
14 | },
15 | },
16 | });
17 |
18 | export default useCounterStore;
19 |
--------------------------------------------------------------------------------
/tools/sloths/src/stores/loader.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia';
2 |
3 | const useLoader = defineStore({
4 | id: 'loader',
5 | state: () => ({
6 | isLoad: false,
7 | }),
8 | });
9 |
10 | export default useLoader;
11 |
--------------------------------------------------------------------------------
/tools/sloths/src/stores/search-text.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia';
2 |
3 | const useSearchText = defineStore({
4 | id: 'searchText',
5 |
6 | state: () => ({
7 | searchText: '',
8 | }),
9 |
10 | actions: {
11 | getSearchText(): string {
12 | return this.searchText;
13 | },
14 |
15 | setSearchText(s: string) {
16 | this.searchText = s;
17 | },
18 | },
19 | });
20 |
21 | export default useSearchText;
22 |
--------------------------------------------------------------------------------
/tools/sloths/src/stores/sloths.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia';
2 | import type { Sloth } from '../common/types';
3 |
4 | const useSlothsStore = defineStore({
5 | id: 'sloths',
6 | state: () => ({
7 | sloths: [] as Sloth[],
8 | }),
9 | });
10 |
11 | export default useSlothsStore;
12 |
--------------------------------------------------------------------------------
/tools/sloths/src/stores/sorting-list.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia';
2 |
3 | const useSortingList = defineStore({
4 | id: 'sortingList',
5 |
6 | state: () => ({
7 | sortingList: '',
8 | }),
9 |
10 | actions: {
11 | getSortingList(): string {
12 | return this.sortingList;
13 | },
14 |
15 | setSortingList(s: string) {
16 | this.sortingList = s;
17 | },
18 | },
19 | });
20 |
21 | export default useSortingList;
22 |
--------------------------------------------------------------------------------
/tools/sloths/src/stores/tag-cloud.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia';
2 |
3 | const useSelectedTags = defineStore({
4 | id: 'tagCloud',
5 |
6 | state: () => ({
7 | selected: [] as string[],
8 | }),
9 |
10 | actions: {
11 | getSelected(): string[] {
12 | return [...this.selected];
13 | },
14 |
15 | setSelected(s: string[]) {
16 | this.selected = [...s];
17 | },
18 | },
19 | });
20 |
21 | export default useSelectedTags;
22 |
--------------------------------------------------------------------------------
/tools/sloths/src/stores/theme.ts:
--------------------------------------------------------------------------------
1 | import { defineStore } from 'pinia';
2 |
3 | const useThemeProp = defineStore({
4 | id: 'theme',
5 | state: () => ({
6 | currTheme: '',
7 | }),
8 | });
9 |
10 | export default useThemeProp;
11 |
--------------------------------------------------------------------------------
/tools/sloths/src/utils/game-utils.ts:
--------------------------------------------------------------------------------
1 | export default function isEven(value: number) {
2 | return !(value % 2);
3 | }
4 |
--------------------------------------------------------------------------------
/tools/sloths/src/utils/userTheme.ts:
--------------------------------------------------------------------------------
1 | export default function getUserTheme(): string {
2 | if (window.matchMedia('(prefers-color-scheme: dark)').matches) {
3 | return 'dark';
4 | }
5 | return 'light';
6 | }
7 |
--------------------------------------------------------------------------------
/tools/sloths/tsconfig.config.json:
--------------------------------------------------------------------------------
1 | {
2 | "extends": "./node_modules/@vue/tsconfig/tsconfig.node.json",
3 | "include": ["vite.config.*", "vitest.config.*", "cypress.config.*"],
4 | "compilerOptions": {
5 | "composite": true,
6 | "types": ["node"],
7 | }
8 | }
9 |
--------------------------------------------------------------------------------