diff --git a/.circleci/config.yml b/.circleci/config.yml index 621db64129..b813779aa7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -33,10 +33,10 @@ install_deploysuite: &install_deploysuite cp ./../buildscript/buildenv.sh . cp ./../buildscript/awsconfiguration.sh . restore_cache_settings_for_build: &restore_cache_settings_for_build - key: docker-node-modules-v3-{{ checksum "package-lock.json" }} + key: docker-node-modules-v4-{{ checksum "package-lock.json" }} save_cache_settings: &save_cache_settings - key: docker-node-modules-v3-{{ checksum "package-lock.json" }} + key: docker-node-modules-v4-{{ checksum "package-lock.json" }} paths: - node_modules @@ -73,7 +73,7 @@ jobs: command: | source awsenvconf source buildenvvar - ./master_deploy.sh -d ECS -e DEV -t latest -s dev_communityapp_taskvar -i communityapp + ./master_deploy.sh -d ECS -e DEV -t latest -s dev_communityapp_taskvar -i communityapp -p FARGATE # Build & Deploy against testing backend # "build-test": @@ -224,7 +224,7 @@ jobs: command: | source awsenvconf source buildenvvar - ./master_deploy.sh -d ECS -e PROD -t latest -s prod_communityapp_taskvar -i communityapp + ./master_deploy.sh -d ECS -e PROD -t latest -s prod_communityapp_taskvar -i communityapp -p FARGATE curl --request POST \ --url https://circleci.com/api/v2/project/github/$CIRCLE_PROJECT_USERNAME/$CIRCLE_PROJECT_REPONAME/pipeline \ --header "Circle-Token: ${CIRCLE_TOKEN}" \ @@ -260,37 +260,37 @@ jobs: # path: ./automated-smoke-test/test-results # Automated Smoke Testing against Production - Smoke-Testing-On-Production: - <<: *defaults - steps: - # Initialization. - - checkout - - setup_remote_docker - - run: *install_dependency - - run: *install_deploysuite - # Restoration of node_modules from cache. - - restore_cache: *restore_cache_settings_for_build - - run: - name: "configuring environment" - command: | - ./awsconfiguration.sh PROD - ./buildenv.sh -e PROD -b prod_communityapp_buildvar,prod_communityapp_deployvar - - run: - name: "Run automation" - no_output_timeout: 20m - command: | - source awsenvconf - source buildenvvar - ./automated-smoke-test/smoketest.sh automation-config-prod.json prod - - store_artifacts: - path: ./automated-smoke-test/test-results + # Smoke-Testing-On-Production: + # <<: *defaults + # steps: + # # Initialization. + # - checkout + # - setup_remote_docker + # - run: *install_dependency + # - run: *install_deploysuite + # # Restoration of node_modules from cache. + # - restore_cache: *restore_cache_settings_for_build + # - run: + # name: "configuring environment" + # command: | + # ./awsconfiguration.sh PROD + # ./buildenv.sh -e PROD -b prod_communityapp_buildvar,prod_communityapp_deployvar + # - run: + # name: "Run automation" + # no_output_timeout: 20m + # command: | + # source awsenvconf + # source buildenvvar + # ./automated-smoke-test/smoketest.sh automation-config-prod.json prod + # - store_artifacts: + # path: ./automated-smoke-test/test-results # Test job for the cases when we do not need deployment. It just rapidly # installs (updates) app dependencies, and runs tests (ESLint, Stylelint, # Jest unit-tests). test: docker: - - image: circleci/node:8.11.1 + - image: circleci/node:10.24.1 steps: - checkout - restore_cache: @@ -360,6 +360,7 @@ workflows: - develop - TOP-1390 - PM-191-2 + - pm-199 # This is alternate dev env for parallel testing # Deprecate this workflow due to beta env shutdown # https://topcoder.atlassian.net/browse/CORE-251 diff --git a/Dockerfile b/Dockerfile index 7691feebdc..0e7f8c6e2c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -2,12 +2,16 @@ # and runs it against the specified Topcoder backend (development or # production) when container is executed. -FROM node:8.11.2 +FROM node:10.24.1 LABEL app="Community App" version="1.0" +RUN useradd -m -s /bin/bash appuser WORKDIR /opt/app COPY . . +RUN chown -R appuser:appuser /opt/app +USER appuser + ################################################################################ # Receiving of build arguments. diff --git a/__tests__/shared/components/Settings/Account/__snapshots__/index.jsx.snap b/__tests__/shared/components/Settings/Account/__snapshots__/index.jsx.snap deleted file mode 100644 index 207666379e..0000000000 --- a/__tests__/shared/components/Settings/Account/__snapshots__/index.jsx.snap +++ /dev/null @@ -1,2132 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders account setting page correctly 1`] = ` - -
-
-

- Account information & Security -

-
- - - -
-
- - Save Changes - -
-
-`; diff --git a/__tests__/shared/components/Settings/Account/index.jsx b/__tests__/shared/components/Settings/Account/index.jsx deleted file mode 100644 index 0bd72d407d..0000000000 --- a/__tests__/shared/components/Settings/Account/index.jsx +++ /dev/null @@ -1,32 +0,0 @@ -import React from 'react'; -import Renderer from 'react-test-renderer/shallow'; - -import Account from 'components/Settings/Account'; - -import userProfile from '../__mocks__/user-profile.json'; -import profileState from '../__mocks__/profile-state.json'; - -const rnd = new Renderer(); - -const settingsUI = { - TABS: { - ACCOUNT: { - MYACCOUNT: 'my account', - // LINKEDACCOUNT: 'linked account', - }, - }, -}; - -it('renders account setting page correctly', () => { - rnd.render(( {}} - clearIncorrectPassword={() => {}} - updateProfile={() => {}} - settingsUI={settingsUI} - />)); - expect(rnd.getRenderOutput()).toMatchSnapshot(); -}); diff --git a/__tests__/shared/components/Settings/Header/__snapshots__/index.jsx.snap b/__tests__/shared/components/Settings/Header/__snapshots__/index.jsx.snap deleted file mode 100644 index bbd94fba03..0000000000 --- a/__tests__/shared/components/Settings/Header/__snapshots__/index.jsx.snap +++ /dev/null @@ -1,33 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders setting page header correctly 1`] = ` -
- - - SAVE CHANGES - - -
-`; diff --git a/__tests__/shared/components/Settings/Header/index.jsx b/__tests__/shared/components/Settings/Header/index.jsx deleted file mode 100644 index 03de63ce50..0000000000 --- a/__tests__/shared/components/Settings/Header/index.jsx +++ /dev/null @@ -1,17 +0,0 @@ -import React from 'react'; -import Renderer from 'react-test-renderer/shallow'; - -import Header from 'components/Settings/Header'; - -import profileState from '../__mocks__/profile-state.json'; - -const rnd = new Renderer(); - -it('renders setting page header correctly', () => { - rnd.render((
{}} - />)); - expect(rnd.getRenderOutput()).toMatchSnapshot(); -}); diff --git a/__tests__/shared/components/Settings/Preferences/Email/__snapshots__/index.jsx.snap b/__tests__/shared/components/Settings/Preferences/Email/__snapshots__/index.jsx.snap deleted file mode 100644 index 585e1c49bf..0000000000 --- a/__tests__/shared/components/Settings/Preferences/Email/__snapshots__/index.jsx.snap +++ /dev/null @@ -1,20 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders email preferences setting page correctly 1`] = ` -
- -
-`; diff --git a/__tests__/shared/components/Settings/Preferences/Email/index.jsx b/__tests__/shared/components/Settings/Preferences/Email/index.jsx deleted file mode 100644 index f49efaae8d..0000000000 --- a/__tests__/shared/components/Settings/Preferences/Email/index.jsx +++ /dev/null @@ -1,11 +0,0 @@ -import React from 'react'; -import Renderer from 'react-test-renderer/shallow'; - -import Email from 'components/Settings/Preferences/Email'; - -const rnd = new Renderer(); - -it('renders email preferences setting page correctly', () => { - rnd.render(()); - expect(rnd.getRenderOutput()).toMatchSnapshot(); -}); diff --git a/__tests__/shared/components/Settings/__mocks__/profile-state.json b/__tests__/shared/components/Settings/__mocks__/profile-state.json deleted file mode 100644 index abd05d4852..0000000000 --- a/__tests__/shared/components/Settings/__mocks__/profile-state.json +++ /dev/null @@ -1,593 +0,0 @@ -{ - "achievements": [ - { - "date": "2016-09-02T00:00:00.000-04:00", - "description": "iOS Developer Challenger Badge" - }, - { - "date": "2015-08-05T00:00:00.000-04:00", - "description": "Participant Badge" - }, - { - "date": "2015-08-05T00:00:00.000-04:00", - "description": "iOS Participant Badge" - }, - { - "date": "2014-07-01T00:00:00.000-04:00", - "description": "Digital Run Top Five" - }, - { - "date": "2014-07-01T00:00:00.000-04:00", - "description": "Digital Run Winner" - }, - { - "date": "2014-02-11T00:00:00.000-05:00", - "description": "First Milestone Prize" - }, - { - "date": "2013-03-15T00:00:00.000-04:00", - "description": "First Forum Post" - }, - { - "date": "2013-03-04T00:00:00.000-05:00", - "description": "First Passing Submission" - }, - { - "date": "2013-02-28T00:00:00.000-05:00", - "description": "First Placement" - }, - { - "date": "2013-02-28T00:00:00.000-05:00", - "description": "First Win" - }, - { - "date": "2012-11-09T00:00:00.000-05:00", - "description": "One Hundred Forum Posts" - }, - { - "date": "2010-10-09T00:00:00.000-04:00", - "description": "Five Hundred Forum Posts" - }, - { - "date": "2009-04-04T00:00:00.000-04:00", - "description": "Twenty Five Placements" - }, - { - "date": "2008-07-01T00:00:00.000-04:00", - "description": "Twenty Five First Placement Win" - }, - { - "date": "2008-06-11T00:00:00.000-04:00", - "description": "One Thousand Forum Posts" - }, - { - "date": "2008-05-12T00:00:00.000-04:00", - "description": "Fifty Passing Submissions" - }, - { - "date": "2008-05-03T00:00:00.000-04:00", - "description": "Fifty Placements" - }, - { - "date": "2008-05-01T00:00:00.000-04:00", - "description": "TopCoder Development Coder of the Month for May 2008" - }, - { - "date": "2007-03-30T00:00:00.000-04:00", - "description": "Fifty First Placement Win" - }, - { - "date": "2006-11-03T00:00:00.000-05:00", - "description": "One Hundred Passing Submissions" - }, - { - "date": "2006-10-28T00:00:00.000-04:00", - "description": "One Hundred First Placement Win" - }, - { - "date": "2006-10-28T00:00:00.000-04:00", - "description": "One hundred Placements" - }, - { - "date": "2006-10-28T00:00:00.000-04:00", - "description": "SRM Engagement Honor" - } - ], - "copilot": false, - "country": "China", - "info": null, - "loadingError": false, - "skills": { - "100": { - "tagName": ".NET", - "hidden": false, - "score": 2, - "sources": [ - "CHALLENGE" - ] - }, - "101": { - "tagName": "ActionScript", - "hidden": false, - "score": 1, - "sources": [ - "CHALLENGE" - ] - }, - "109": { - "tagName": "Android", - "hidden": false, - "score": 1, - "sources": [ - "CHALLENGE" - ] - }, - "110": { - "tagName": "AngularJS", - "hidden": false, - "score": 10, - "sources": [ - "CHALLENGE" - ] - }, - "115": { - "tagName": "Apache Kafka", - "hidden": false, - "score": 1, - "sources": [ - "USER_ENTERED" - ] - }, - "117": { - "tagName": "API", - "hidden": false, - "score": 4, - "sources": [ - "CHALLENGE" - ] - }, - "127": { - "tagName": "Blackberry SDK", - "hidden": false, - "score": 1, - "sources": [ - "CHALLENGE" - ] - }, - "132": { - "tagName": "C#", - "hidden": false, - "score": 1, - "sources": [ - "CHALLENGE" - ] - }, - "153": { - "tagName": "CSS", - "hidden": false, - "score": 10, - "sources": [ - "CHALLENGE" - ] - }, - "154": { - "tagName": "CSS3", - "hidden": false, - "score": 1, - "sources": [ - "USER_ENTERED" - ] - }, - "163": { - "tagName": "Docker", - "hidden": false, - "score": 5, - "sources": [ - "CHALLENGE" - ] - }, - "170": { - "tagName": "EJB", - "hidden": false, - "score": 18, - "sources": [ - "CHALLENGE" - ] - }, - "171": { - "tagName": "Elasticsearch", - "hidden": false, - "score": 1, - "sources": [ - "CHALLENGE" - ] - }, - "177": { - "tagName": "Express", - "hidden": false, - "score": 1, - "sources": [ - "CHALLENGE" - ] - }, - "182": { - "tagName": "Flex", - "hidden": false, - "score": 3, - "sources": [ - "CHALLENGE", - "USER_ENTERED" - ] - }, - "186": { - "tagName": "Force.Com Sites", - "hidden": false, - "score": 1, - "sources": [ - "CHALLENGE" - ] - }, - "211": { - "tagName": "Hibernate", - "hidden": false, - "score": 12, - "sources": [ - "CHALLENGE" - ] - }, - "212": { - "tagName": "HTML", - "hidden": false, - "score": 6, - "sources": [ - "CHALLENGE" - ] - }, - "213": { - "tagName": "HTML5", - "hidden": false, - "score": 12, - "sources": [ - "CHALLENGE", - "USER_ENTERED" - ] - }, - "214": { - "tagName": "HTTP", - "hidden": false, - "score": 3, - "sources": [ - "CHALLENGE" - ] - }, - "219": { - "tagName": "IBM DB2", - "hidden": false, - "score": 5, - "sources": [ - "CHALLENGE", - "USER_ENTERED" - ] - }, - "229": { - "tagName": "IBM Websphere Application Server", - "hidden": false, - "score": 3, - "sources": [ - "CHALLENGE" - ] - }, - "232": { - "tagName": "IBM WebSphere MQ", - "hidden": false, - "score": 1, - "sources": [ - "CHALLENGE" - ] - }, - "244": { - "tagName": "J2EE", - "hidden": false, - "score": 15, - "sources": [ - "CHALLENGE" - ] - }, - "247": { - "tagName": "Java", - "hidden": false, - "score": 123, - "sources": [ - "CHALLENGE" - ] - }, - "248": { - "tagName": "JavaScript", - "hidden": false, - "score": 20, - "sources": [ - "CHALLENGE" - ] - }, - "249": { - "tagName": "JBoss Seam", - "hidden": false, - "score": 3, - "sources": [ - "CHALLENGE" - ] - }, - "250": { - "tagName": "JDBC", - "hidden": false, - "score": 3, - "sources": [ - "CHALLENGE" - ] - }, - "254": { - "tagName": "JPA", - "hidden": false, - "score": 9, - "sources": [ - "CHALLENGE" - ] - }, - "255": { - "tagName": "jQuery", - "hidden": false, - "score": 2, - "sources": [ - "CHALLENGE" - ] - }, - "258": { - "tagName": "JSF", - "hidden": false, - "score": 2, - "sources": [ - "CHALLENGE", - "USER_ENTERED" - ] - }, - "259": { - "tagName": "JSON", - "hidden": false, - "score": 1, - "sources": [ - "CHALLENGE" - ] - }, - "260": { - "tagName": "JSP", - "hidden": false, - "score": 21, - "sources": [ - "CHALLENGE", - "USER_ENTERED" - ] - }, - "276": { - "tagName": "Maven", - "hidden": false, - "score": 1, - "sources": [ - "CHALLENGE" - ] - }, - "281": { - "tagName": "MongoDB", - "hidden": false, - "score": 1, - "sources": [ - "CHALLENGE" - ] - }, - "284": { - "tagName": "MySql", - "hidden": false, - "score": 7, - "sources": [ - "CHALLENGE", - "USER_ENTERED" - ] - }, - "286": { - "tagName": "Node.js", - "hidden": false, - "score": 18, - "sources": [ - "CHALLENGE", - "USER_ENTERED" - ] - }, - "295": { - "tagName": "Oracle Database", - "hidden": false, - "score": 14, - "sources": [ - "CHALLENGE" - ] - }, - "303": { - "tagName": "PHP", - "hidden": false, - "score": 1, - "sources": [ - "CHALLENGE" - ] - }, - "306": { - "tagName": "PostgreSQL", - "hidden": false, - "score": 8, - "sources": [ - "CHALLENGE" - ] - }, - "315": { - "tagName": "React.js", - "hidden": false, - "score": 1, - "sources": [ - "USER_ENTERED" - ] - }, - "323": { - "tagName": "REST", - "hidden": false, - "score": 5, - "sources": [ - "CHALLENGE" - ] - }, - "328": { - "tagName": "Salesforce", - "hidden": false, - "score": 2, - "sources": [ - "CHALLENGE" - ] - }, - "337": { - "tagName": "Servlet", - "hidden": false, - "score": 2, - "sources": [ - "CHALLENGE" - ] - }, - "344": { - "tagName": "Sharepoint 3.0", - "hidden": false, - "score": 2, - "sources": [ - "CHALLENGE", - "USER_ENTERED" - ] - }, - "354": { - "tagName": "Spring", - "hidden": false, - "score": 15, - "sources": [ - "CHALLENGE" - ] - }, - "355": { - "tagName": "SQL", - "hidden": false, - "score": 4, - "sources": [ - "CHALLENGE" - ] - }, - "356": { - "tagName": "SQL Server", - "hidden": false, - "score": 2, - "sources": [ - "CHALLENGE" - ] - }, - "362": { - "tagName": "Struts", - "hidden": false, - "score": 3, - "sources": [ - "CHALLENGE" - ] - }, - "387": { - "tagName": "Web Services", - "hidden": false, - "score": 8, - "sources": [ - "CHALLENGE" - ] - }, - "401": { - "tagName": "XML", - "hidden": false, - "score": 6, - "sources": [ - "CHALLENGE" - ] - }, - "402": { - "tagName": "XSL", - "hidden": false, - "score": 2, - "sources": [ - "CHALLENGE", - "USER_ENTERED" - ] - } - }, - "stats": null, - "profileForHandle": "tcscoder", - "linkedAccounts": [ - { - "userId": "623633", - "name": "tcscoder", - "email": "tcscoder@gmail.com", - "providerType": "github", - "provider": null, - "context": null, - "social": true, - "enterprise": false, - "emailVerified": false - }, - { - "userId": "1233342", - "name": "1233342", - "email": "", - "providerType": "stackoverflow", - "provider": null, - "context": null, - "social": true, - "enterprise": false, - "emailVerified": false - } - ], - "externalLinks": [ - { - "userId": 22655076, - "key": "4c7136cdbbf227274e49c475e7541abf", - "handle": "tcscoder", - "description": "Search the world's information, including webpages, images, videos and more. Google has many special features to help you find exactly what you're looking for.", - "entities": null, - "keywords": null, - "title": "Google", - "images": "https://www.google.com/images/branding/googlelogo/1x/googlelogo_white_background_color_272x92dp.png", - "source": "embed.ly", - "synchronizedAt": 1525560141959, - "URL": "https://www.google.com" - } - ], - "externalAccounts": { - "userId": 22655076, - "handle": "tcscoder", - "behance": null, - "bitbucket": null, - "dribbble": null, - "github": null, - "linkedin": null, - "stackoverflow": null, - "twitter": null, - "updatedAt": null, - "createdAt": null, - "createdBy": null, - "updatedBy": null - }, - "emailPreferences": { - "TOPCODER_NL_DESIGN": true, - "TOPCODER_NL_DEV": true, - "TOPCODER_NL_GEN": true - }, - "credential": { - "activationCode": "SDUUH(HFS", - "resetToken": null, - "hasPassword": true - } -} \ No newline at end of file diff --git a/__tests__/shared/components/Settings/__mocks__/props-match.json b/__tests__/shared/components/Settings/__mocks__/props-match.json deleted file mode 100644 index 3995d403ea..0000000000 --- a/__tests__/shared/components/Settings/__mocks__/props-match.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "isExact": true, - "params": { - "settingsTab": "profile" - }, - "path": "/settings/:settingsTab(profile|tools|account|preferences)", - "url": "/settings/profile" -} \ No newline at end of file diff --git a/__tests__/shared/components/Settings/__mocks__/user-profile.json b/__tests__/shared/components/Settings/__mocks__/user-profile.json deleted file mode 100644 index b2dd0838f0..0000000000 --- a/__tests__/shared/components/Settings/__mocks__/user-profile.json +++ /dev/null @@ -1,81 +0,0 @@ -{ - "maxRating": { - "rating": 2162, - "track": "DEVELOP", - "subTrack": "DEVELOPMENT" - }, - "userId": 22655076, - "firstName": "Mike", - "lastName": "Smith", - "description": "Hello", - "otherLangName": "Som", - "handle": "tcscoder", - "handleLower": "tcscoder", - "status": "ACTIVE", - "email": "tcscoder@gmail.com", - "addresses": [ - { - "streetAddr1": "Street line 1, #432", - "streetAddr2": "", - "city": "Cheng Du", - "zip": "610101", - "stateCode": "Sichuan", - "type": "HOME", - "updatedAt": null, - "createdAt": null, - "createdBy": "", - "updatedBy": "" - } - ], - "homeCountryCode": "CHN", - "competitionCountryCode": "CHN", - "photoURL": "https://topcoder-prod-media.s3.amazonaws.com/member/profile/tcscoder-1525559661069.png", - "tracks": [ - "DEVELOP" - ], - "updatedAt": "2018-05-05T22:34Z", - "createdAt": "2006-10-06T08:49Z", - "createdBy": "22655076", - "updatedBy": "22655076", - "groups": [ - { - "id": "20000010", - "modifiedBy": null, - "modifiedAt": null, - "createdBy": "8547899", - "createdAt": "2017-09-11T13:54:47.000Z", - "name": "Blockchain", - "description": "Blockchain", - "privateGroup": true, - "selfRegister": true, - "subGroups": null, - "parentGroup": null - }, - { - "id": "20000013", - "modifiedBy": null, - "modifiedAt": null, - "createdBy": "8547899", - "createdAt": "2017-10-19T10:54:47.000Z", - "name": "Veterans", - "description": "Veterans", - "privateGroup": true, - "selfRegister": true, - "subGroups": null, - "parentGroup": null - }, - { - "id": "20000015", - "modifiedBy": null, - "modifiedAt": null, - "createdBy": "8547899", - "createdAt": "2017-11-06T15:49:35.000Z", - "name": "Cognitive", - "description": "Cognitive Community", - "privateGroup": true, - "selfRegister": true, - "subGroups": null, - "parentGroup": null - } - ] -} \ No newline at end of file diff --git a/__tests__/shared/components/Settings/__snapshots__/index.jsx.snap b/__tests__/shared/components/Settings/__snapshots__/index.jsx.snap deleted file mode 100644 index d73c732fee..0000000000 --- a/__tests__/shared/components/Settings/__snapshots__/index.jsx.snap +++ /dev/null @@ -1,3042 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`renders account setting page correctly 1`] = ` -
- -
-
- - -
-
-`; - -exports[`renders preferences setting page correctly 1`] = ` -
- -
-
- - -
-
-`; - -exports[`renders profile setting page correctly 1`] = ` -
- -
-
- - -
-
-`; - -exports[`renders tools setting page correctly 1`] = ` -
- -
-
- - -
-
-`; diff --git a/__tests__/shared/components/Settings/index.jsx b/__tests__/shared/components/Settings/index.jsx deleted file mode 100644 index 98fcde7a81..0000000000 --- a/__tests__/shared/components/Settings/index.jsx +++ /dev/null @@ -1,83 +0,0 @@ -import React from 'react'; -import Renderer from 'react-test-renderer/shallow'; - -import Settings from 'components/Settings'; - -import userProfile from './__mocks__/user-profile.json'; -import profileState from './__mocks__/profile-state.json'; -import propsMatch from './__mocks__/props-match.json'; - -const rnd = new Renderer(); - -it('renders profile setting page correctly', () => { - rnd.render(( {}} - showXlBadge={() => {}} - profile={userProfile} - profileState={profileState} - settingsPageState={{}} - lookupData={{}} - updateProfile={() => {}} - uploadPhoto={() => {}} - deletePhoto={() => {}} - addSkill={() => {}} - hideSkill={() => {}} - match={propsMatch} - />)); - expect(rnd.getRenderOutput()).toMatchSnapshot(); -}); - -it('renders account setting page correctly', () => { - rnd.render(( {}} - showXlBadge={() => {}} - profile={userProfile} - profileState={profileState} - settingsPageState={{}} - updatePassword={() => {}} - clearIncorrectPassword={() => {}} - updateProfile={() => {}} - match={propsMatch} - />)); - expect(rnd.getRenderOutput()).toMatchSnapshot(); -}); - -it('renders tools setting page correctly', () => { - rnd.render(( {}} - showXlBadge={() => {}} - profile={userProfile} - profileState={profileState} - settingsPageState={{}} - match={propsMatch} - />)); - expect(rnd.getRenderOutput()).toMatchSnapshot(); -}); - -it('renders preferences setting page correctly', () => { - rnd.render(( {}} - showXlBadge={() => {}} - profile={userProfile} - profileState={profileState} - settingsPageState={{}} - match={propsMatch} - />)); - expect(rnd.getRenderOutput()).toMatchSnapshot(); -}); diff --git a/__tests__/shared/components/challenge-listing/Sidebar/__snapshots__/Footer.jsx.snap b/__tests__/shared/components/challenge-listing/Sidebar/__snapshots__/Footer.jsx.snap index 88fbc5b716..d5a3513f5d 100644 --- a/__tests__/shared/components/challenge-listing/Sidebar/__snapshots__/Footer.jsx.snap +++ b/__tests__/shared/components/challenge-listing/Sidebar/__snapshots__/Footer.jsx.snap @@ -69,7 +69,7 @@ exports[`Matches shallow shapshot 1`] = ` className="src-shared-components-challenge-listing-Sidebar-Footer-___style__copyright___ghkHg" > Topcoder © - 2024 + 2025

`; diff --git a/__tests__/shared/components/tc-communities/NewsletterSignup.jsx b/__tests__/shared/components/tc-communities/NewsletterSignup.jsx deleted file mode 100644 index 4fdbfe1737..0000000000 --- a/__tests__/shared/components/tc-communities/NewsletterSignup.jsx +++ /dev/null @@ -1,72 +0,0 @@ -import React from 'react'; -import Rnd from 'react-test-renderer/shallow'; -import TU from 'react-dom/test-utils'; -import NewsletterSignup from 'components/tc-communities/NewsletterSignup'; - -const rnd = new Rnd(); - -test('Snapshot match', () => { - rnd.render(( - - )); - expect(rnd.getRenderOutput()).toMatchSnapshot(); - - rnd.render(( - - )); - expect(rnd.getRenderOutput()).toMatchSnapshot(); -}); - -class Wrapper extends React.Component { - componentDidMount() {} - - render() { - return ( - - ); - } -} - -const instance = TU.renderIntoDocument(( - -)); - -describe('handle click', () => { - beforeEach(() => jest.clearAllMocks()); - - test('onTitleClick', () => { - const matches = TU.scryRenderedDOMComponentsWithTag(instance, 'button'); - expect(matches.length).toBe(1); - TU.Simulate.click(matches[0]); - }); -}); diff --git a/__tests__/shared/components/tc-communities/__snapshots__/NewsletterSignup.jsx.snap b/__tests__/shared/components/tc-communities/__snapshots__/NewsletterSignup.jsx.snap deleted file mode 100644 index dd6ae1c390..0000000000 --- a/__tests__/shared/components/tc-communities/__snapshots__/NewsletterSignup.jsx.snap +++ /dev/null @@ -1,47 +0,0 @@ -// Jest Snapshot v1, https://goo.gl/fbAQLP - -exports[`Snapshot match 1`] = ` - -`; - -exports[`Snapshot match 2`] = ` - -`; diff --git a/__tests__/shared/components/tc-communities/communities/community-2/__snapshots__/Learn.jsx.snap b/__tests__/shared/components/tc-communities/communities/community-2/__snapshots__/Learn.jsx.snap index 922eede706..07cfe014b4 100644 --- a/__tests__/shared/components/tc-communities/communities/community-2/__snapshots__/Learn.jsx.snap +++ b/__tests__/shared/components/tc-communities/communities/community-2/__snapshots__/Learn.jsx.snap @@ -255,19 +255,5 @@ exports[`Match shadow snapshot 1`] = ` title="Useful Links" /> - `; diff --git a/__tests__/shared/components/tc-communities/communities/demo-expert/__snapshots__/Learn.jsx.snap b/__tests__/shared/components/tc-communities/communities/demo-expert/__snapshots__/Learn.jsx.snap index 442c1cebdf..22130a3c9f 100644 --- a/__tests__/shared/components/tc-communities/communities/demo-expert/__snapshots__/Learn.jsx.snap +++ b/__tests__/shared/components/tc-communities/communities/demo-expert/__snapshots__/Learn.jsx.snap @@ -410,19 +410,5 @@ exports[`Snapshot match 1`] = ` title="Useful Links" /> - `; diff --git a/__tests__/shared/components/tc-communities/communities/taskforce/__snapshots__/Home.jsx.snap b/__tests__/shared/components/tc-communities/communities/taskforce/__snapshots__/Home.jsx.snap index ac2d5bdc21..efb0463e56 100644 --- a/__tests__/shared/components/tc-communities/communities/taskforce/__snapshots__/Home.jsx.snap +++ b/__tests__/shared/components/tc-communities/communities/taskforce/__snapshots__/Home.jsx.snap @@ -212,19 +212,5 @@ exports[`Match shadow snapshot 1`] = ` } } /> - `; diff --git a/__tests__/shared/components/tc-communities/communities/tc-prod-dev/__snapshots__/Learn.jsx.snap b/__tests__/shared/components/tc-communities/communities/tc-prod-dev/__snapshots__/Learn.jsx.snap index 54022b665c..cb16633b29 100644 --- a/__tests__/shared/components/tc-communities/communities/tc-prod-dev/__snapshots__/Learn.jsx.snap +++ b/__tests__/shared/components/tc-communities/communities/tc-prod-dev/__snapshots__/Learn.jsx.snap @@ -395,19 +395,5 @@ exports[`Snapshot match 1`] = ` title="Useful Links" /> - `; diff --git a/__tests__/shared/utils/__snapshots__/markdown.js.snap b/__tests__/shared/utils/__snapshots__/markdown.js.snap index 449da8d15c..5dc7969857 100644 --- a/__tests__/shared/utils/__snapshots__/markdown.js.snap +++ b/__tests__/shared/utils/__snapshots__/markdown.js.snap @@ -1203,7 +1203,7 @@ Array [ A list item with a code block:

- <code goes here> + <code> @@ -1294,7 +1294,7 @@ end tell ampersands and angle brackets. For example, this:

, - <div class="footer"> + <div> © 2004 Foo Corporation </div> diff --git a/automated-smoke-test/Dockerfile b/automated-smoke-test/Dockerfile deleted file mode 100644 index b228769e64..0000000000 --- a/automated-smoke-test/Dockerfile +++ /dev/null @@ -1,32 +0,0 @@ -FROM node:10.17.0-stretch -RUN apt update -RUN apt install sudo -RUN sudo apt-get update; sudo apt-get install -y openjdk-8-jre openjdk-8-jre-headless openjdk-8-jdk openjdk-8-jdk-headless; -RUN curl --silent --show-error --location --fail --retry 3 --output /tmp/google-chrome-stable_current_amd64.deb https://dl.google.com/linux/direct/google-chrome-stable_current_amd64.deb \ - && (sudo dpkg -i /tmp/google-chrome-stable_current_amd64.deb || sudo apt-get -fy install) \ - && rm -rf /tmp/google-chrome-stable_current_amd64.deb \ - && sudo sed -i 's|HERE/chrome"|HERE/chrome" --disable-setuid-sandbox --no-sandbox|g' \ - "/opt/google/chrome/google-chrome" \ - && google-chrome --version -RUN export CHROMEDRIVER_RELEASE=$(curl --location --fail --retry 3 http://chromedriver.storage.googleapis.com/LATEST_RELEASE) \ - && curl --silent --show-error --location --fail --retry 3 --output /tmp/chromedriver_linux64.zip "http://chromedriver.storage.googleapis.com/$CHROMEDRIVER_RELEASE/chromedriver_linux64.zip" \ - && cd /tmp \ - && unzip chromedriver_linux64.zip \ - && rm -rf chromedriver_linux64.zip \ - && sudo mv chromedriver /usr/local/bin/chromedriver \ - && sudo chmod +x /usr/local/bin/chromedriver \ - && chromedriver --version -RUN sudo apt-get install -y libgconf-2-4 -RUN sudo apt-get install -y xvfb -RUN sudo apt-get install -y jq -ENV DISPLAY :99 -RUN printf '#!/bin/sh\nXvfb :99 -screen 0 1280x1024x24 &\nexec "$@"\n' > /tmp/entrypoint \ - && chmod +x /tmp/entrypoint \ - && sudo mv /tmp/entrypoint /docker-entrypoint.sh - -COPY . /automated-smoke-test -WORKDIR /automated-smoke-test -RUN npm install -RUN ./node_modules/.bin/webdriver-manager update --versions.chrome=="$(google-chrome -version)" -ENTRYPOINT ["/docker-entrypoint.sh"] -CMD ["/bin/sh"] \ No newline at end of file diff --git a/automated-smoke-test/config/automation-config-dev.json b/automated-smoke-test/config/automation-config-dev.json index 4df4b85ad3..9ac9bf711d 100644 --- a/automated-smoke-test/config/automation-config-dev.json +++ b/automated-smoke-test/config/automation-config-dev.json @@ -86,7 +86,6 @@ "allNotificationsUrl": "https://community-app.topcoder-dev.com/notifications", "policiesUrl": "https://community-app.topcoder-dev.com/policy", "username": "tester1234", - "password": "appirio123", "email": "sathya.jayabal@gmail.com", "challangesLinks": { "rssFeedUrl": "http://feeds.topcoder-dev.com/challenges/feed", diff --git a/automated-smoke-test/config/automation-config-local.json b/automated-smoke-test/config/automation-config-local.json index 79f61ba285..c2ca342f56 100644 --- a/automated-smoke-test/config/automation-config-local.json +++ b/automated-smoke-test/config/automation-config-local.json @@ -81,7 +81,6 @@ "allNotificationsUrl": "http://localhost:3000/notifications", "policiesUrl": "http://localhost:3000/policy", "username": "Tonyj", - "password": "appirio123", "email": "topcoderconnect@gmail.com", "challangesLinks": { "rssFeedUrl": "http://feeds.topcoder.com/challenges/feed", diff --git a/automated-smoke-test/config/automation-config-prod.json b/automated-smoke-test/config/automation-config-prod.json index ed2fc420de..d05c56008c 100644 --- a/automated-smoke-test/config/automation-config-prod.json +++ b/automated-smoke-test/config/automation-config-prod.json @@ -81,7 +81,6 @@ "allNotificationsUrl": "https://www.topcoder.com/notifications", "policiesUrl": "https://www.topcoder.com/policy", "username": "CustomerUser", - "password": "appirio123", "email": "topcoderconnect@gmail.com", "challangesLinks": { "rssFeedUrl": "http://feeds.topcoder.com/challenges/feed", diff --git a/automated-smoke-test/test-data/test-data.json b/automated-smoke-test/test-data/test-data.json index 02aa602405..98fcf8a0bc 100644 --- a/automated-smoke-test/test-data/test-data.json +++ b/automated-smoke-test/test-data/test-data.json @@ -1,7 +1,6 @@ { "login": { - "invalidUsername": "gjhhvv", - "invalidPassword": "invalidpassword" + "invalidUsername": "gjhhvv" }, "tools": { "subscription": "Sample A", diff --git a/config/default.js b/config/default.js index e30ec05227..f5424d3504 100644 --- a/config/default.js +++ b/config/default.js @@ -132,8 +132,8 @@ module.exports = { INFO: { DESIGN_CHALLENGES: 'http://help.topcoder.com/hc/en-us/categories/202610437-DESIGN', DESIGN_CHALLENGE_CHECKPOINTS: 'https://help.topcoder.com/hc/en-us/articles/219240807-Multi-Round-Checkpoint-Design-Challenges', - DESIGN_CHALLENGE_SUBMISSION: 'http://help.topcoder.com/hc/en-us/articles/219122667-Formatting-Your-Submission-for-Design-Challenges', - DESIGN_CHALLENGE_TYPES: 'http://help.topcoder.com/hc/en-us/articles/217481388-Choosing-a-Design-Challenge', + DESIGN_CHALLENGE_SUBMISSION: 'https://www.topcoder.com/thrive/articles/Formatting%20Your%20Submission%20for%20Design%20Challenges', + DESIGN_CHALLENGE_TYPES: 'https://www.topcoder.com/thrive/articles/How%20To%20Compete%20in%20Design', RELIABILITY_RATINGS_AND_BONUSES: 'https://www.topcoder.com/thrive/articles/Development%20Reliability%20Ratings%20and%20Bonuses', STOCK_ART_POLICY: 'http://help.topcoder.com/hc/en-us/articles/217481408-Policy-for-Stock-Artwork-in-Design-Submissions', STUDIO_FONTS_POLICY: diff --git a/docs/contentful/AppComponent.md b/docs/contentful/AppComponent.md index 12c3980e17..a937f7b942 100644 --- a/docs/contentful/AppComponent.md +++ b/docs/contentful/AppComponent.md @@ -46,8 +46,6 @@ Render top spots and list of competitors on specific TCO track. A block that fetches and renders a job listing page driven by recruitCRM. -### Type = `EmailSubscribeForm` - Generic subscribe for MailChimp tags component. - **listId** | **String (Required).** diff --git a/docs/contentful/custom-inline-components-in-markdown-fields.md b/docs/contentful/custom-inline-components-in-markdown-fields.md index da252c165b..4961ffe946 100644 --- a/docs/contentful/custom-inline-components-in-markdown-fields.md +++ b/docs/contentful/custom-inline-components-in-markdown-fields.md @@ -69,22 +69,6 @@ other types too. | listId | | ID of MailChimp list to subscribe. | | interests | empty string | Optional. commas separated string of group ids to which user should be subscribed | -- #### NewsletterSignupForMembers - **Sample use:** `` - - Renders a newsletter signup button that takes user email from his profile - information. If the user is not-authenticated, it gets him to the login or - registration page, and subscribes him on return. Accepts the following props: - - | Param | Default | Description | - | --- | --- | --- | - | label | Subscribe for Newsletter | Optional. Custom label to show on the button. | - | listId | | ID of MailChimp list to subscribe. | - | tags | | ID of MailChimp tags to subscribe. | - | buttonTheme | primary-green-md | Theme key(`tc-` is omitted) for the button. See https://community-app.topcoder.com/examples/contentful/contentblock/3k7k1JpnSvIRrJYWs4izYi | - | title | Sign up for the Topcoder Newsletter | Modal title | - | desc | Do you want to subscribe to this newsletter? | Modal description | - - #### VideoModalButton *Example:* `` @@ -98,14 +82,6 @@ other types too. component works only with YouTube videos, and the URL should be similar to `https://www.youtube.com/embed/mD12LIqdxqk` (). -- #### NewsletterArchive - *Example:* `` - - A list of archive links sorted by descending `sent_date` from a MailChimp's campaign folder. Sould be working under any MarkdownParser component. - - The properties are: - - `name` - the unique name of the camplaing foler. It has to be only one name entity. If those duplicate first found will be picked up and rest ignored. - ## Links - #### Link diff --git a/docs/pwa/nginx/server.key b/docs/pwa/nginx/server.key deleted file mode 100644 index 3e46bd6691..0000000000 --- a/docs/pwa/nginx/server.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQDXKekFdnLsjrnq -4RMF/V6ewrDRwzt9gVJXX8aEemq5wDjrnK1q2SJBrEMQw72T1oIt8TJs+d6HLc0K -DX3MILdix/r/+ML5bVjTd6HdzqXnbsd9omvZ3a43QKLxGCvqwe0iN8C7106++nik -3issH6qiQh5p5ERN8gApSyj0/PIu051YCNL8SpsqDiRHtWzZt07ncPFPueINXdRu -AEb7pod7tIvBnI2kudJx4d2AX+lE7eOhsvCr0eHS3/V03BlprAt3qw7c2ZwLxTYZ -D/l6NgCoy6AQfq9d7XikTVFx9ZKiuCPVS11PzI6G2pbx5Y6ewHdcfLnPVIDKPfMh -L3SjmDTNAgMBAAECggEAOLf3kVUUHn/RSrViSmXsF3XDHsiUWhVJG3dH4YxTrfua -BaIbpNrwSNecJkMzKlGVp365iDimDIRqVIgR7UmCjiuhYvC0lQPaMoSKyum6mjN9 -qwSx4ZCqaC5FxcBVc2EDnc2MpPew7m8gdnWKc+s1E+jSE5/00YdFu5zwgwRa4zSx -TquwlMGd6AcE1J5YbxYGJRztAl2VKguBJFcSnnFef8xY18GoEO1lt43ef9ijsfL3 -mBccrlLWQmc1CxM8zZ83lD1yW41bcwMhx7XCgRZjhDtNmbyWWJOYoFwojtAxFqG4 -VHFKjY+kNgIWjKZim84GA3tUPS/L832GXYk6SyC6kQKBgQD/HsnCryGTaitjwn+5 -FbPWlBnnGn1hxE36g0u1B3A/mQ3Jut949Dsm9vEoS1gHOQBCc5cE3RXNZ6iZdSDc -Lf9YzZnchIgjauU9bqkZVI2RSPnNOTjWjXhGtrZxrc4eckRWqbChmYX0qCxokwhb -leIdmJy7Y0Q6ttVGAHySoC/h7wKBgQDX59mKR1Gm7rKcEqW2aWhz878Xft/OHchh -THF9EUGHWXOYiKDAPxV6+xg2ZZaPUorMdp588iC3dd0YRn/KSkFlYWIgA8yYkjI7 -Al6pwGgOPw8k2/t1Rxfw2NUJr/19dAqMSyxDZ6W1OsGsdoAIgOMQxx12zENZpX6y -xcewsWNhAwKBgQC33vbHa/WlC4YONmZbfTrKUp+AouTvC86v2OU9qgjKrYL0e80I -ne3sHVqeEf915S08t5aGmNlX23f2ciamyjgZRsW324VLEYX7CsCxUvFdXt07fhxq -9jdTr+g6cmv2IaEDXPXC4qVbOcIX9LC3YYVAk3eSzu6j6pY4B63A99bK3QKBgQDE -d/mQiGe4BVxJA/sB7Bed9D9+7PhSAu4WBE79pVdBCFhVhHbrmjw8xgN5dKY2U8F0 -X7jHMDovWDTSY0zkUwABdkWppmtmpxrIcdacmDbYR+/K9dd0GDaj91ydTSXaJF94 -3Osxhz7WlNoqy0ak9kwqN1cLhMMA78VEfw/BLRqm6wKBgGUZNlOXQjcAcFjZ12Z4 -3X3tOWjwAPx2D5kT99Jh2BDgzjOci303MDnxI+mb6BQY32mz5+2OlD+bz2qYHVPp -9+Ir9WNbIl+DCUadRcPuYPAwPSftBEKzH901BBXHnbSkLSWocvLqYxUBjJ64KTh0 -2OTOU4OPRrct2tauUUyPRiBX ------END PRIVATE KEY----- diff --git a/docs/swagger.yaml b/docs/swagger.yaml deleted file mode 100644 index 19cc61f8d6..0000000000 --- a/docs/swagger.yaml +++ /dev/null @@ -1,196 +0,0 @@ -openapi: 3.0.0 -info: - title: Community APP - description: Community APP - version: 1.0.0 -servers: - - url: http://local.topcoder-dev.com:3000 -tags: - - name: Profile -paths: - /api/recruit/profile: - get: - tags: - - Profile - description: | - Get Profile of current user - - **Authorization** All topcoder members are allowed. - security: - - bearerAuth: [] - responses: - "200": - description: OK - content: - application/json: - schema: - type: array - items: - $ref: "#/components/schemas/Profile" - "401": - description: Not authenticated - content: - application/json: - schema: - $ref: "#/components/schemas/AuthError" - "403": - description: Forbidden - content: - application/json: - schema: - $ref: "#/components/schemas/AuthError" - "404": - description: Not Found - content: - application/json: - schema: - $ref: "#/components/schemas/Profile" - "500": - description: Internal Server Error - content: - text/plain:: - schema: - type: string - post: - tags: - - Profile - description: | - Update Profile details of current user - **Authorization** All topcoder members are allowed. - security: - - bearerAuth: [] - requestBody: - content: - multipart/form-data: - schema: - $ref: "#/components/schemas/ProfileUpdate" - responses: - "204": - description: OK - "400": - description: Bad request - content: - application/json: - schema: - oneOf: - - $ref: "#/components/schemas/JoiError" - - $ref: "#/components/schemas/Error" - "401": - description: Not authenticated - content: - application/json: - schema: - $ref: "#/components/schemas/AuthError" - "403": - description: Forbidden - content: - application/json: - schema: - $ref: "#/components/schemas/AuthError" - "404": - description: Not Found - content: - application/json: - schema: - $ref: "#/components/schemas/Error" - "500": - description: Internal Server Error - content: - text/plain:: - schema: - type: string -components: - securitySchemes: - bearerAuth: - type: http - scheme: bearer - bearerFormat: JWT - schemas: - Profile: - required: - - availability - properties: - phone: - type: string - description: "The phone number of the user" - example: "+1123226666" - resume: - type: string - description: "The resume of the user" - availability: - type: boolean - description: "The availability of the user" - default: true - example: true - skill: - type: string - description: "The candidate's skills separated via ," - example: "Java,Angular,SQL Server,JavaScript" - salaryExpectation: - type: integer - description: "The candidate expected salary" - hasProfile: - type: boolean - description: "Whether has profile for the user" - ProfileUpdate: - required: - - phone - - availability - - city - - countryName - properties: - phone: - type: string - description: "The phone number of the user" - example: "(123) 456-7890" - city: - type: string - description: "The member's city" - countryName: - type: string - description: "The member's country" - resume: - type: string - format: binary - description: "The resume file of the user" - availability: - type: boolean - description: "The availability of the user" - example: true - Error: - properties: - error: - type: boolean - example: true - status: - type: integer - example: 404 - url: - type: string - format: uri - errObj: - type: object - JoiError: - required: - - message - properties: - message: - type: string - AuthError: - properties: - version: - type: string - result: - type: object - properties: - success: - type: boolean - example: false - status: - type: integer - example: 403 - content: - type: object - properties: - message: - type: string diff --git a/package.json b/package.json index 45c9302fe6..3ed6237f7a 100644 --- a/package.json +++ b/package.json @@ -33,8 +33,8 @@ }, "homepage": "https://github.com/topcoder-platform/community-app#readme", "engines": { - "node": "^8.11.2", - "npm": "^5.6.0" + "node": "^10.24.1", + "npm": "^6.14.12" }, "dependencies": { "@hapi/joi": "^16.1.4", @@ -172,7 +172,8 @@ "url-parse": "^1.4.1", "uuid": "^3.3.2", "valid-url": "^1.0.9", - "xml2json": "^0.11.2" + "xml2json": "^0.11.2", + "xss": "^1.0.15" }, "devDependencies": { "@commitlint/cli": "^8.3.5", diff --git a/src/server/index.js b/src/server/index.js index 393a72b9a7..3ee3671a78 100644 --- a/src/server/index.js +++ b/src/server/index.js @@ -22,14 +22,12 @@ import { factory as reducerFactory } from 'reducers'; import { redux, server as serverFactory } from 'topcoder-react-utils'; import { getRates as getExchangeRates } from 'services/money'; import { toJson as xmlToJson } from 'utils/xml2json'; +import { promisify } from 'util'; import cdnRouter from './routes/cdn'; -import mailChimpRouter from './routes/mailchimp'; import mockDocuSignFactory from './__mocks__/docu-sign-mock'; import recruitCRMRouter from './routes/recruitCRM'; import mmLeaderboardRouter from './routes/mmLeaderboard'; -import gSheetsRouter from './routes/gSheet'; -import blogRouter from './routes/blog'; import feedsRouter from './routes/feeds'; /* Dome API for topcoder communities */ @@ -42,9 +40,40 @@ global.atob = atob; const CMS_BASE_URL = `https://app.contentful.com/spaces/${config.SECRET.CONTENTFUL.SPACE_ID}`; -let ts = path.resolve(__dirname, '../../.build-info'); -ts = JSON.parse(fs.readFileSync(ts)); -ts = moment(ts.timestamp).valueOf(); +const getTimestamp = async () => { + let timestamp; + try { + const filePath = path.resolve(__dirname, '../../.build-info'); + if (!filePath.startsWith(path.resolve(__dirname, '../../'))) { + throw new Error('Invalid file path detected'); + } + + const MAX_FILE_SIZE = 10 * 1024; // 10 KB max file size + const stats = await promisify(fs.stat)(filePath); + if (stats.size > MAX_FILE_SIZE) { + throw new Error('File is too large and may cause DoS issues'); + } + + const fileContent = await promisify(fs.readFile)(filePath, 'utf-8'); + + let tsData; + try { + tsData = JSON.parse(fileContent); + } catch (parseErr) { + throw new Error('Invalid JSON format in file'); + } + + if (!tsData || !tsData.timestamp) { + throw new Error('Timestamp is missing in the JSON file'); + } + + timestamp = moment(tsData.timestamp).valueOf(); + } catch (err) { + console.error('Error:', err.message); + } + + return timestamp; +}; const sw = `sw.js${process.env.NODE_ENV === 'production' ? '' : '?debug'}`; const swScope = '/challenges'; // we are currently only interested in improving challenges pages @@ -52,7 +81,7 @@ const swScope = '/challenges'; // we are currently only interested in improving const tcoPattern = new RegExp(/^tco\d{2}\.topcoder(?:-dev)?\.com$/i); const universalNavUrl = config.UNIVERSAL_NAV_URL; -const EXTRA_SCRIPTS = [ +const getExtraScripts = ts => [ `