diff --git a/.circleci/config.yml b/.circleci/config.yml index ac35f0cf5..c30ac9bde 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -24,24 +24,14 @@ jobs: wget http://downloads.sourceforge.net/project/jboss/JBoss/JBoss-4.2.3.GA/jboss-4.2.3.GA-jdk6.zip unzip jboss-4.2.3.GA-jdk6.zip cd project - - run: - name: checking out build repo - command: | - git clone --branch master https://github.com/topcoder-platform/tc-deploy-scripts ../buildscript - #git clone --branch master git@github.com:appirio-tech/ops.git ../direct-config-update - #git clone --branch master https://$GITUSER:$GITPASSWD@github.com/appirio-tech/ops ../direct-config-update - checkout - - run: - name: copying configuration file - command: | - cp ./../buildscript/direct/conf/dev/token.properties.enc . - openssl enc -aes-256-cbc -d -in token.properties.enc -out token.properties -k $SECPASSWD - run: name: Installation of build dependencies. command: | javac -version ant -version aws --version + ./buildproperties.sh -e DEV -k directapp ant package-direct package-static-direct - store_artifacts: path: ./direct.jar @@ -148,24 +138,14 @@ jobs: wget http://downloads.sourceforge.net/project/jboss/JBoss/JBoss-4.2.3.GA/jboss-4.2.3.GA-jdk6.zip unzip jboss-4.2.3.GA-jdk6.zip cd project - - run: - name: checking out build repo - command: | - git clone --branch master https://github.com/topcoder-platform/tc-deploy-scripts ../buildscript - #git clone --branch master git@github.com:appirio-tech/ops.git ../direct-config-update - #git clone --branch master https://$GITUSER:$GITPASSWD@github.com/appirio-tech/ops ../direct-config-update - checkout - - run: - name: copying configuration file - command: | - cp ./../buildscript/direct/conf/prod/token.properties.enc . - openssl enc -aes-256-cbc -d -in token.properties.enc -out token.properties -k $SECPASSWD - run: name: Installation of build dependencies. command: | javac -version ant -version aws --version + ./buildproperties.sh -e PROD -k directapp ant package-direct package-static-direct - store_artifacts: path: ./direct.jar diff --git a/README.md b/README.md index 405610ab3..0551134a0 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ direct-app ========== ## building -To build, download the docker build container that has all of the build dependencies. You can then run the container to build your local source code. +To build, download the docker build container that has all of the build dependencies. You can then run the container to build your local source code. 1. Clone the github source directory 2. Rename `token.properties.docker` to `token.properties` in the source directory diff --git a/build-package.sh b/build-package.sh index 33f4ce17a..665ecc682 100755 --- a/build-package.sh +++ b/build-package.sh @@ -8,6 +8,7 @@ then fi VER=`date "+%Y%m%d%H%M"` +SCRIPTDIR="./scripts" directapp_cdpacakge() { @@ -16,7 +17,7 @@ directapp_cdpacakge() source $BUILD_VARIABLE_FILE_NAME AWS_CD_PACKAGE_NAME="${APPNAME}-${PACKAGETYPE}-${VER}.zip" PACAKAGE_LOCATION="dist-${PACKAGETYPE}" - SCRIPTDIR="./../buildscript/direct/scripts" +# SCRIPTDIR="./../buildscript/direct/scripts" rm -rf $PACAKAGE_LOCATION mkdir $PACAKAGE_LOCATION #cd $PACAKAGE_LOCATION diff --git a/build.xml b/build.xml index a5db1b321..e6a622978 100644 --- a/build.xml +++ b/build.xml @@ -359,6 +359,7 @@ + @@ -526,7 +527,8 @@ - + + diff --git a/buildproperties.sh b/buildproperties.sh new file mode 100755 index 000000000..8446769cf --- /dev/null +++ b/buildproperties.sh @@ -0,0 +1,103 @@ +#!/bin/bash +KEY_LOCATION="" +BUILDENV_LIST="" +usage() +{ +cat << EOF +usage: $0 options +This script need to be executed with below option. +OPTIONS: + -e environment + -b Security file location GIT|AWS + -k key location +EOF +} +#log Function - Used to provide information of execution information with date and time +log() +{ + echo "`date +'%D %T'` : $1" +} +track_error() +{ + if [ $1 != "0" ]; then + log "$2 exited with error code $1" + log "completed execution IN ERROR at `date`" + exit $1 + fi + +} +download_buildenvfile() +{ + if [ -z "$BUILDENV_LIST" ]; + then + if [ -z "$KEY_LOCATION" ]; + then + track_error $? "Please provide the file list using -b or file location -k or both -b and -k " + else + aws s3 sync s3://tc-buildproperties-${ENV_CONFIG}/$KEY_LOCATION . + track_error $? "Environment setting" + fi + + else + Buffer_seclist=$(echo $BUILDENV_LIST | sed 's/,/ /g' ) + for listname in $Buffer_seclist; + do + if [ -z "$KEY_LOCATION" ]; + then + aws s3 cp s3://tc-buildproperties-${ENV_CONFIG}/$listname . + track_error $? "Environment setting" + else + aws s3 cp s3://tc-buildproperties-${ENV_CONFIG}/$KEY_LOCATION/$listname . + track_error $? "Environment setting" + fi + done + fi + +} + +configure_aws_cli() { + aws --version + aws configure set aws_access_key_id $AWS_ACCESS_KEY_ID + aws configure set aws_secret_access_key $AWS_SECRET_ACCESS_KEY + aws configure set default.region $AWS_REGION + aws configure set default.output json + log "Configured AWS CLI." +} + +while getopts .b:e:k:. OPTION +do + case $OPTION in + e) + ENV=$OPTARG + ;; + b) + BUILDENV_LIST=$OPTARG + ;; + k) + KEY_LOCATION=$OPTARG + ;; + ?) + log "additional param required" + usage + exit + ;; + esac +done + +AWS_ACCESS_KEY_ID=$(eval "echo \$${ENV}_AWS_ACCESS_KEY_ID") +AWS_SECRET_ACCESS_KEY=$(eval "echo \$${ENV}_AWS_SECRET_ACCESS_KEY") +AWS_REGION=$(eval "echo \$${ENV}_AWS_REGION") +if [ -z $AWS_REGION ]; +then +AWS_REGION="us-east-1" +fi +if [ -z $AWS_ACCESS_KEY_ID ] || [ -z $AWS_SECRET_ACCESS_KEY ] ; +then + log "AWS Secret Parameters are not configured in circleci/environment" + usage + exit 1 +else + configure_aws_cli +fi +ENV_CONFIG=`echo "$ENV" | tr '[:upper:]' '[:lower:]'` +download_buildenvfile diff --git a/components/deliverable_management/src/java/main/com/topcoder/management/deliverable/Upload.java b/components/deliverable_management/src/java/main/com/topcoder/management/deliverable/Upload.java index 3d4fd2545..069feed34 100644 --- a/components/deliverable_management/src/java/main/com/topcoder/management/deliverable/Upload.java +++ b/components/deliverable_management/src/java/main/com/topcoder/management/deliverable/Upload.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006,2010 TopCoder Inc., All Rights Reserved. + * Copyright (C) 2006 - 2018 TopCoder Inc., All Rights Reserved. */ package com.topcoder.management.deliverable; @@ -19,9 +19,13 @@ * This class is highly mutable. All fields can be changed. *

* + *

+ * Version 1.3 - Topcoder - Change Download URL in Direct Application + * - Add url property + *

* @author aubergineanode, singlewood * @author TCSDESIGNER, TCSDEVELOPER - * @version 1.2 + * @version 1.3 */ public class Upload extends AuditedDeliverableStructure { /** @@ -93,6 +97,12 @@ public class Upload extends AuditedDeliverableStructure { */ private String description; + /** + * Represent the s3 url + * + */ + private String url; + /** * Creates a new Upload. */ @@ -267,4 +277,22 @@ public boolean isValidToPersist() { && (parameter != null) && (super.isValidToPersist())); } + + /** + * Get url + * + * @return url + */ + public String getUrl() { + return url; + } + + /** + * Set url + * + * @param url url + */ + public void setUrl(String url) { + this.url = url; + } } diff --git a/components/deliverable_management/src/java/main/com/topcoder/management/deliverable/persistence/sql/SqlUploadPersistence.java b/components/deliverable_management/src/java/main/com/topcoder/management/deliverable/persistence/sql/SqlUploadPersistence.java index cc6b225c1..f59d3dcc3 100644 --- a/components/deliverable_management/src/java/main/com/topcoder/management/deliverable/persistence/sql/SqlUploadPersistence.java +++ b/components/deliverable_management/src/java/main/com/topcoder/management/deliverable/persistence/sql/SqlUploadPersistence.java @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006-2012 TopCoder Inc., All Rights Reserved. + * Copyright (C) 2006-2018 TopCoder Inc., All Rights Reserved. */ package com.topcoder.management.deliverable.persistence.sql; @@ -193,7 +193,14 @@ *
  • Update {@link #loadUpload(CustomResultSet)} to load the project phase id.
  • * *

    - * + * + *

    + * Version 1.6 - Topcoder - Change Download URL in Direct Application + *

      + *
    1. Update {@link #loadUpload(CustomResultSet)} to load url.
    2. + *
    + *

    + * * Thread Safety: This class is immutable and thread-safe in the sense that multiple threads can not * corrupt its internal data structures. However, the results if used from multiple threads can be unpredictable as the * database is changed from different threads. This can equally well occur when the component is used on multiple @@ -202,7 +209,7 @@ * * @author aubergineanode, saarixx, urtks, George1 * @author TCSDESIGNER, TCSDEVELOPER - * @version 1.5 + * @version 1.6 */ public class SqlUploadPersistence implements UploadPersistence { @@ -2525,6 +2532,7 @@ private Upload loadUpload(CustomResultSet resultSet) throws UploadPersistenceExc upload.setCreationTimestamp(resultSet.getDate("upload_create_date")); upload.setModificationUser(resultSet.getString("upload_modify_user")); upload.setModificationTimestamp(resultSet.getDate("upload_modify_date")); + upload.setUrl(resultSet.getString("upload_url")); upload.setProject(resultSet.getLong("project_id")); if (resultSet.getObject("project_phase_id") != null) { diff --git a/conf/AwsS3Credentials.properties b/conf/AwsS3Credentials.properties new file mode 100644 index 000000000..04a49ab84 --- /dev/null +++ b/conf/AwsS3Credentials.properties @@ -0,0 +1,2 @@ +accessKey = @aws_s3_access_key@ +secretKey = @aws_s3_secret_key@ \ No newline at end of file diff --git a/conf/components/com/topcoder/util/config/ConfigManager.properties b/conf/components/com/topcoder/util/config/ConfigManager.properties index 0640fe5de..df0fbe12b 100644 --- a/conf/components/com/topcoder/util/config/ConfigManager.properties +++ b/conf/components/com/topcoder/util/config/ConfigManager.properties @@ -10,6 +10,7 @@ com.cronos.onlinereview.services.uploads.impl.DefaultManagersProvider = onlineRe com.cronos.onlinereview.services.uploads.impl.DefaultUploadServices = onlineReviewUpload_config.xml com.cronos.onlinereview.services.uploads.impl.DefaultUploadExternalServices = onlineReviewUpload_config.xml com.topcoder.servlet.request.LocalFileUpload = onlineReviewUpload_config.xml +com.topcoder.servlet.request.LocalStudioFileUpload = onlineReviewUpload_config.xml com.topcoder.project.service.ProjectServicesFactory = projectServices_config.xml com.topcoder.project.service.impl.ProjectServicesImpl = projectServices_config.xml diff --git a/conf/objectFactory_config.xml b/conf/objectFactory_config.xml index be024a927..ec8cbfe31 100644 --- a/conf/objectFactory_config.xml +++ b/conf/objectFactory_config.xml @@ -1010,6 +1010,7 @@ upload.resource_id AS resource_id, upload.project_phase_id AS project_phase_id, upload.parameter AS upload_parameter, + upload.url AS upload_url, upload_type_lu.upload_type_id AS upload_type_id, upload_type_lu.create_user AS upload_type_create_user, upload_type_lu.create_date AS upload_type_create_date, diff --git a/conf/onlineReviewUpload_config.xml b/conf/onlineReviewUpload_config.xml index ac873dd92..9d795145b 100644 --- a/conf/onlineReviewUpload_config.xml +++ b/conf/onlineReviewUpload_config.xml @@ -64,4 +64,24 @@ false + + + + -1 + + + -1 + + + @studio_file_storage_location@ + + + @studio_file_storage_location@ + + + false + + diff --git a/conf/web/WEB-INF/applicationContext.xml b/conf/web/WEB-INF/applicationContext.xml index ab84ef6a7..26d5871b7 100644 --- a/conf/web/WEB-INF/applicationContext.xml +++ b/conf/web/WEB-INF/applicationContext.xml @@ -174,6 +174,12 @@ + + + com.topcoder.servlet.request.LocalStudioFileUpload + + + @@ -943,21 +949,27 @@ class="com.topcoder.direct.services.view.action.contest.DownloadAllSoftwareSubmissionsAction" scope="prototype" parent="baseDirectStrutsAction"> + + + + + + + + * *

    - * + * + *

    + * Version 1.3 - Topcoder - Change Download URL in Direct Application + * - Add support download from S3 + * - Add support for download studio + *

    + * * @author TCSASSEMBLER - * @version 1.2 + * @version 1.3 */ public class DownloadAllSoftwareSubmissionsAction extends ContestAction { @@ -126,6 +135,11 @@ public class DownloadAllSoftwareSubmissionsAction extends ContestAction { */ private static final String ALL_SUBMISSIONS = "All_Submissions.zip"; + /** + * Resource property for "Handle" + */ + private static final String RESOURCE_PROPERTY_HANDLE = "Handle"; + /** * Represents the upload parameters which are used to retrieve the uploaded files. */ @@ -136,6 +150,10 @@ public class DownloadAllSoftwareSubmissionsAction extends ContestAction { */ private FileUpload fileUpload; + /** + * Represents the FileUpload service for studio. It will be injected by Spring. + */ + private FileUpload studioFileUpload; /** * The round type of the software contest. @@ -165,6 +183,11 @@ public class DownloadAllSoftwareSubmissionsAction extends ContestAction { */ private SoftwareCompetition contest; + /** + * S3 bucket + */ + private String s3Bucket; + /** *

    * Creates a DownloadAllSoftwareSubmissionsAction instance. @@ -259,34 +282,55 @@ public InputStream getInputStream() throws Exception { PipedInputStream in = new PipedInputStream(); PipedOutputStream out = new PipedOutputStream(in); final ZipOutputStream zos = new ZipOutputStream(out); - new Thread(new Runnable(){ + new Thread(new Runnable() { public void run() { byte[] buffer = new byte[8192]; int read; InputStream is = null; try { for (Submission sub : submissionsToDownload) { - UploadedFile file = fileUpload.getUploadedFile(sub.getUpload().getParameter()); - is = file.getInputStream(); String submissionFileZipName; - - if(isCopilotPosting) { - // special handling for the copilot posting submission, prefix the submitter's handle - final String copilotHandle = getUserService().getUserHandle(Long.parseLong(sub.getUpload().getCreationUser())); - String ext = FilenameUtils.getExtension(file.getRemoteFileName()); - if(ext != null && ext.trim().length() > 0) { - ext = "." + ext; + // url != null is s3 + if (sub.getUpload().getUrl() != null) { + S3Object s3Object = DirectUtils.getS3Client().getObject(new GetObjectRequest(s3Bucket, + DirectUtils.getS3FileKey(sub.getUpload().getUrl()))); + is = s3Object.getObjectContent(); + submissionFileZipName = DirectUtils.getS3FileKey(sub.getUpload().getUrl()); + } else { + UploadedFile file; + if (DirectUtils.isStudio(contest)) { + Long userId = null; + String handle = null; + for (Resource r : contest.getResources()) { + if (r.getId() == sub.getUpload().getOwner()) { + userId = r.getUserId(); + handle = r.getProperty(RESOURCE_PROPERTY_HANDLE); + } + } + file = studioFileUpload.getUploadedFile(DirectUtils.createStudioLocalFilePath(contest.getId(), userId, handle, + sub.getUpload().getParameter())); } else { - ext = ""; + file = fileUpload.getUploadedFile(sub.getUpload().getParameter()); + } + is = file.getInputStream(); + + if (isCopilotPosting) { + // special handling for the copilot posting submission, prefix the submitter's handle + final String copilotHandle = getUserService().getUserHandle(Long.parseLong(sub.getUpload().getCreationUser())); + String ext = FilenameUtils.getExtension(file.getRemoteFileName()); + if (ext != null && ext.trim().length() > 0) { + ext = "." + ext; + } else { + ext = ""; + } + submissionFileZipName = copilotHandle + COPILOT_POSTING_SUBMISSION + + ext; + + is = DirectUtils.appendStringToFilesInZip(file, copilotHandle); + } else { + submissionFileZipName = "Submission-" + sub.getId() + "-" + file.getRemoteFileName(); } - submissionFileZipName = copilotHandle + COPILOT_POSTING_SUBMISSION - + ext; - - is = DirectUtils.appendStringToFilesInZip(file, copilotHandle); - } else { - submissionFileZipName = "Submission-" + sub.getId() + "-" + file.getRemoteFileName(); } - // create an entry for each file ZipEntry outputEntry = new ZipEntry(submissionFileZipName); @@ -375,4 +419,39 @@ public void setFileUpload(FileUpload fileUpload) { public void setRoundType(ContestRoundType roundType) { this.roundType = roundType; } + + /** + * Get S3 bucket + * + * @return s3 bucket name + */ + public String getS3Bucket() { + return s3Bucket; + } + + /** + * Set S3 bucket + * @param s3Bucket S3 bucket name + */ + public void setS3Bucket(String s3Bucket) { + this.s3Bucket = s3Bucket; + } + + /** + * Get FileUpload instance for studio + * + * @return FileUpload instance + */ + public FileUpload getStudioFileUpload() { + return studioFileUpload; + } + + /** + * Set FileUpload for studio + * + * @param studioFileUpload FileUpload instance + */ + public void setStudioFileUpload(FileUpload studioFileUpload) { + this.studioFileUpload = studioFileUpload; + } } diff --git a/src/java/main/com/topcoder/direct/services/view/action/contest/DownloadSoftwareSubmissionAction.java b/src/java/main/com/topcoder/direct/services/view/action/contest/DownloadSoftwareSubmissionAction.java index 197f4d06b..e63f3d242 100644 --- a/src/java/main/com/topcoder/direct/services/view/action/contest/DownloadSoftwareSubmissionAction.java +++ b/src/java/main/com/topcoder/direct/services/view/action/contest/DownloadSoftwareSubmissionAction.java @@ -1,8 +1,10 @@ /* - * Copyright (C) 2011 - 2013 TopCoder Inc., All Rights Reserved. + * Copyright (C) 2011 - 2018 TopCoder Inc., All Rights Reserved. */ package com.topcoder.direct.services.view.action.contest; +import com.amazonaws.services.s3.model.GetObjectRequest; +import com.amazonaws.services.s3.model.S3Object; import com.topcoder.direct.services.view.action.BaseDirectStrutsAction; import com.topcoder.direct.services.view.dto.contest.ContestType; import com.topcoder.direct.services.view.util.DirectUtils; @@ -28,9 +30,15 @@ *

  • Updated {@link #getContentDisposition()} to prefix copilot handle to the copilot posting submission name
  • * *

    - * + * + *

    + * Version 1.2 - Topcoder - Change Download URL in Direct Application + * - Add support download from S3 + * - Add support for download studio + *

    + * * @author TCSASSEMBLER - * @version 1.1 (Release Assembly - TC Cockpit Misc Bug Fixes) + * @version 1.2 * @since TCCC-2802 */ public class DownloadSoftwareSubmissionAction extends BaseDirectStrutsAction { @@ -39,6 +47,11 @@ public class DownloadSoftwareSubmissionAction extends BaseDirectStrutsAction { */ private static final long serialVersionUID = 1870450815370143413L; + /** + * Resource property for "Handle" + */ + private static final String RESOURCE_PROPERTY_HANDLE = "Handle"; + /** * Represents the submission id the user want to download. */ @@ -65,6 +78,11 @@ public class DownloadSoftwareSubmissionAction extends BaseDirectStrutsAction { */ private FileUpload fileUpload; + /** + * Represents the FileUpload service for studio. It will be injected by Spring. + */ + private FileUpload studioFileUpload; + /** * The SoftwareCompetition instance representing the contest the submission is downloaded from. * @@ -72,18 +90,28 @@ public class DownloadSoftwareSubmissionAction extends BaseDirectStrutsAction { */ private SoftwareCompetition contest; + /** + * S3 url of uploaded file. Null if it use local file + */ + private String s3Url; + + /** + * S3 bucket + */ + private String s3Bucket; + /** *

    * Executes the action. It will get the uploaded file the user want to download. *

    - * + * * @throws Exception * is any error occurs. */ @Override protected void executeAction() throws Exception { // get the submission of the project - Submission[] submissions = getContestServiceFacade().getSoftwareProjectSubmissions(getCurrentUser(), projectId); + Submission[] submissions = getContestServiceFacade().getSoftwareProjectSubmissions(getCurrentUser(), projectId); // check whether the project contains the submission the user want to download for (Submission sub : submissions) { if (sub.getUpload() != null && sub.getId() == submissionId) { @@ -99,20 +127,43 @@ protected void executeAction() throws Exception { contest = getContestServiceFacade().getSoftwareContestByProjectId(getCurrentUser(), projectId); - uploadedFile = fileUpload.getUploadedFile(submission.getUpload().getParameter()); + if (submission.getUpload().getUrl() == null) { + if (DirectUtils.isStudio(contest)) { + Long userId = null; + String handle = null; + for (Resource r : contest.getResources()) { + if (r.getId() == submission.getUpload().getOwner()) { + userId = r.getUserId(); + handle = r.getProperty(RESOURCE_PROPERTY_HANDLE); + } + } + + uploadedFile = studioFileUpload.getUploadedFile(DirectUtils.createStudioLocalFilePath(contest.getId(), userId, handle, + submission.getUpload().getParameter())); + } else { + uploadedFile = fileUpload.getUploadedFile(submission.getUpload().getParameter()); + } + } else { + s3Url = submission.getUpload().getUrl(); + } } /** * Gets the InputStream of the download. - * + * * @return the InputStream of the download. * @throws Exception * if any error occurs when getting the input stream of the uploaded file. */ public InputStream getInputStream() throws Exception { + if (s3Url != null) { + S3Object s3Object = DirectUtils.getS3Client().getObject(new GetObjectRequest(s3Bucket, + DirectUtils.getS3FileKey(s3Url))); + return s3Object.getObjectContent(); + } - if(contest.getProjectHeader().getProjectCategory().getId() == ContestType.COPILOT_POSTING.getId()) { + if (contest.getProjectHeader().getProjectCategory().getId() == ContestType.COPILOT_POSTING.getId()) { // it's copilot posting, append user handle to each file in the copilot posting submission Resource[] resources = contest.getResources(); long userId = 0; @@ -131,12 +182,15 @@ public InputStream getInputStream() throws Exception { /** * Gets the content disposition of the uploaded file. - * + * * @return the content disposition of the upload file. * @throws Exception * if any error occurs when getting the file name of the uploaded file. */ public String getContentDisposition() throws Exception { + if (s3Url != null) { + return "attachment; filename=\"submission-" + submission.getId() + "-" + DirectUtils.getS3FileKey(s3Url) + "\""; + } if (contest.getProjectHeader().getProjectCategory().getId() == ContestType.COPILOT_POSTING.getId()) { // it's copilot posting, append user handle to each file in the copilot posting submission @@ -148,7 +202,6 @@ public String getContentDisposition() throws Exception { break; } } - return "attachment; filename=\"submission-" + getUserService().getUserHandle(userId) + "-" + uploadedFile.getRemoteFileName() + "\""; @@ -160,7 +213,7 @@ public String getContentDisposition() throws Exception { /** * Gets the submission id the user want to download. - * + * * @return the submission id the user want to download. */ public long getSubmissionId() { @@ -169,7 +222,7 @@ public long getSubmissionId() { /** * Sets the submission id the user want to download. - * + * * @param submissionId * the submission id the user want to download. */ @@ -178,7 +231,7 @@ public void setSubmissionId(long submissionId) { } /** Gets the project id of the upload. - * + * * @return the project id of the upload. */ public long getProjectId() { @@ -187,7 +240,7 @@ public long getProjectId() { /** * Sets the project id of the upload. - * + * * @param projectId * the project id of the upload. */ @@ -197,7 +250,7 @@ public void setProjectId(long projectId) { /** * Gets the FileUpload service. - * + * * @return the FileUpload service. */ public FileUpload getFileUpload() { @@ -206,7 +259,7 @@ public FileUpload getFileUpload() { /** * Sets the FileUpload service. - * + * * @param fileUpload * the FileUpload service. */ @@ -227,4 +280,39 @@ public void setFileUpload(FileUpload fileUpload) { private InputStream prefixHandleToSubmissionFile(UploadedFile submissionFile, long userId) throws Exception { return DirectUtils.appendStringToFilesInZip(submissionFile, getUserService().getUserHandle(userId)); } + + /** + * Get S3 bucket + * + * @return s3 bucket name + */ + public String getS3Bucket() { + return s3Bucket; + } + + /** + * Set S3 bucket + * @param s3Bucket S3 bucket name + */ + public void setS3Bucket(String s3Bucket) { + this.s3Bucket = s3Bucket; + } + + /** + * Get FileUpload instance for studio + * + * @return FileUpload instance + */ + public FileUpload getStudioFileUpload() { + return studioFileUpload; + } + + /** + * Set FileUpload for studio + * + * @param studioFileUpload FileUpload instance + */ + public void setStudioFileUpload(FileUpload studioFileUpload) { + this.studioFileUpload = studioFileUpload; + } } diff --git a/src/java/main/com/topcoder/direct/services/view/util/DirectUtils.java b/src/java/main/com/topcoder/direct/services/view/util/DirectUtils.java index f9f391aa2..e69dc2153 100644 --- a/src/java/main/com/topcoder/direct/services/view/util/DirectUtils.java +++ b/src/java/main/com/topcoder/direct/services/view/util/DirectUtils.java @@ -3,6 +3,8 @@ */ package com.topcoder.direct.services.view.util; +import com.amazonaws.auth.PropertiesCredentials; +import com.amazonaws.services.s3.AmazonS3Client; import com.opensymphony.xwork2.ActionContext; import com.topcoder.clients.dao.ProjectContestFeePercentageService; import com.topcoder.clients.dao.ProjectContestFeeService; @@ -116,6 +118,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.net.URL; import java.nio.channels.FileLock; import java.sql.Connection; import java.sql.PreparedStatement; @@ -752,9 +755,15 @@ * Version 2.4 - Quick72Hrs!! Topcoder - Remove VM Management Feature In Direct App version 1.0 * - remove VM related functionality *

    - * + * + *

    + * Version 2.5 - Topcoder - Change Download URL in Direct Application + * - Add {@link #s3Client} + * - Add {@link #getS3Client()} to get S3 client instance + * - Add {@link #getS3FileKey(String)} to get S3 key from url + *

    * @author BeBetter, isv, flexme, Blues, Veve, GreatKevin, minhu, FireIce, Ghost_141, jiajizhou86, TCSCODER - * @version 2.4 + * @version 2.5 */ public final class DirectUtils { @@ -1011,13 +1020,30 @@ public final class DirectUtils { "WHERE ls.example = 0 AND ls.long_component_state_id = lcs.long_component_state_id " + "AND lcs.round_id = r.round_id "; + /** + * AWS S3 client + */ + private static final AmazonS3Client s3Client; + + /** + * The AWS credentials file. + */ + private static final String AWS_CREDENTIALS_FILE = "AwsS3Credentials.properties"; /** * The jackson object mapping which is used to deserialize json return from API to domain model. */ protected static final ObjectMapper objectMapper; + static { objectMapper = new ObjectMapper(); + try { + ClassLoader loader = DirectUtils.class.getClassLoader(); + URL credentialURL = loader.getResource(AWS_CREDENTIALS_FILE); + s3Client = new AmazonS3Client(new PropertiesCredentials(new File(credentialURL.getFile()))); + } catch (Throwable e) { + throw new RuntimeException("Failed load to Amazon S3 Client", e); + } } /** @@ -4036,4 +4062,40 @@ public static void getMMRegistantsSubmissionInfo(List registrants, L DatabaseUtils.close(conn); } } + + public static AmazonS3Client getS3Client() { + return s3Client; + } + + /** + * Get S3 key from S3 url + * + * @param url S3 url + * @return S3 key + * @throws Exception if any exceptions occurs + */ + public static String getS3FileKey(String url) throws Exception { + String path = new URL(url).getPath(); + int sep = path.lastIndexOf( '/' ); + return ( sep < 0 ) ? path : path.substring( sep + 1 ); + } + + /** + * Create local studio path + * @param projectId project id + * @param userId user id the owner of file + * @param userHandle user handle of owner of file + * @param parameter upload parameter of file + */ + public static String createStudioLocalFilePath(long projectId, long userId, String userHandle, String parameter) { + StringBuffer buf = new StringBuffer(80); + buf.append(projectId); + buf.append(System.getProperty("file.separator")); + buf.append(userHandle.toLowerCase()); + buf.append("_"); + buf.append(userId); + buf.append(System.getProperty("file.separator")); + buf.append(parameter); + return buf.toString(); + } } diff --git a/src/web/WEB-INF/editCockpitProject.jsp b/src/web/WEB-INF/editCockpitProject.jsp index edabccb40..d8892e649 100644 --- a/src/web/WEB-INF/editCockpitProject.jsp +++ b/src/web/WEB-INF/editCockpitProject.jsp @@ -220,7 +220,7 @@
    -

    Appirio Project Manager :

    +

    Wipro Project Manager :

      @@ -274,7 +274,7 @@
    -

    Project SVN Address :

    +

    Project Repo :

    diff --git a/src/web/WEB-INF/includes/contest/submissionViewer/slotTitle.jsp b/src/web/WEB-INF/includes/contest/submissionViewer/slotTitle.jsp index b15f3fe45..fdf271c5b 100644 --- a/src/web/WEB-INF/includes/contest/submissionViewer/slotTitle.jsp +++ b/src/web/WEB-INF/includes/contest/submissionViewer/slotTitle.jsp @@ -18,6 +18,7 @@ +
    @@ -43,9 +44,12 @@
    + + + diff --git a/src/web/WEB-INF/includes/popups.jsp b/src/web/WEB-INF/includes/popups.jsp index 6a036d30d..2f25013e7 100644 --- a/src/web/WEB-INF/includes/popups.jsp +++ b/src/web/WEB-INF/includes/popups.jsp @@ -2499,7 +2499,7 @@
    - Manage Appirio Project Manager + Manage Wipro Project Manager Close
    diff --git a/src/web/WEB-INF/project-overview.jsp b/src/web/WEB-INF/project-overview.jsp index c81ebfc9c..dc2806868 100644 --- a/src/web/WEB-INF/project-overview.jsp +++ b/src/web/WEB-INF/project-overview.jsp @@ -474,14 +474,14 @@
    -
    -

    Appirio Project Managers :

    +
    +

    Wipro Project Managers :

    Add - Appirio Project Manager + Wipro Project Manager diff --git a/src/web/WEB-INF/tags/links/studioSubmissionDownload.tag b/src/web/WEB-INF/tags/links/studioSubmissionDownload.tag index 8c02799a4..e582c4363 100644 --- a/src/web/WEB-INF/tags/links/studioSubmissionDownload.tag +++ b/src/web/WEB-INF/tags/links/studioSubmissionDownload.tag @@ -16,13 +16,11 @@ <%@ attribute name="submissionId" required="true" type="java.lang.Long" %> <%@ attribute name="styleClass" required="false" type="java.lang.String" %> <%@ attribute name="original" required="false" type="java.lang.Boolean" %> +<%@ attribute name="contestId" required="false" type="java.lang.Long" %> - - - - + diff --git a/src/web/WEB-INF/tags/ui/studioSubmissionGridItem.tag b/src/web/WEB-INF/tags/ui/studioSubmissionGridItem.tag index 261e64e9d..dab5e2d21 100644 --- a/src/web/WEB-INF/tags/ui/studioSubmissionGridItem.tag +++ b/src/web/WEB-INF/tags/ui/studioSubmissionGridItem.tag @@ -32,7 +32,7 @@
    - + diff --git a/src/web/WEB-INF/tags/ui/studioSubmissionListItem.tag b/src/web/WEB-INF/tags/ui/studioSubmissionListItem.tag index 52448b56a..a9865a65c 100644 --- a/src/web/WEB-INF/tags/ui/studioSubmissionListItem.tag +++ b/src/web/WEB-INF/tags/ui/studioSubmissionListItem.tag @@ -38,7 +38,7 @@ - ${submissionId} (Download) + ${submissionId} (Download) diff --git a/src/web/scripts/editCockpitProject.js b/src/web/scripts/editCockpitProject.js index d5f30dd71..93b667a74 100644 --- a/src/web/scripts/editCockpitProject.js +++ b/src/web/scripts/editCockpitProject.js @@ -1281,7 +1281,7 @@ $(document).ready(function (e) { if(modal.find('.addUserForm .addUserLeft ul li.selected').length > 1 && modal.attr('id') == 'appirioManagersModal') { - showErrors("A project can only have 1 Appirio Project Manager"); + showErrors("A project can only have 1 Wipro Project Manager"); return; } diff --git a/src/web/scripts/launch/entity.js b/src/web/scripts/launch/entity.js index a33dfb6ec..20e5e3c45 100644 --- a/src/web/scripts/launch/entity.js +++ b/src/web/scripts/launch/entity.js @@ -1,5 +1,5 @@ /* - * Copyright (C) 2010 - 2018 TopCoder Inc., All Rights Reserved. + * Copyright (C) 2010 - 2018 TopCoder Inc., All Rights Reserved. */ /** * This javascript file defines classes to store informations about contest. @@ -67,11 +67,11 @@ * Version 1.10(TOPCODER - IMPROVE USER MANAGEMENT BEHAVIOR FOR PROJECT PERMISSIONS & NOTIFICATIONS) * - Refactor constant for copilot posting * - * Version 1.11 (Topcoder - Support Points Prize Type For Challenges) - * - Add support for points prize type - * + * Version 1.11 (Topcoder - Support Points Prize Type For Challenges) + * - Add support for points prize type + * * @author duxiaoyang, bugbuka, GreatKevin, TCSCODER - * @version 1.11 + * @version 1.11 */ if(!com) { var com = {}; @@ -95,7 +95,7 @@ var CONTEST_DETAILED_STATUS_ACTIVE_PUBLIC =2 ; var CONTEST_DETAILED_STATUS_SCHEDULED =9 ; var CHECKPOINT_PRIZE_TYPE_ID = 14; var CONTEST_PRIZE_TYPE_ID = 15; -var CHALLENGE_POINT_TYPE_ID = 16; +var CHALLENGE_POINT_TYPE_ID = 16; /** @@ -119,8 +119,8 @@ com.topcoder.direct.Prize = function(place, amount, prizeType, numberOfSubmissio this.prizeType.description = "Contest Prize"; } else if (prizeType == CHECKPOINT_PRIZE_TYPE_ID) { this.prizeType.description = "Checkpoint Prize"; - } else if (prizeType == CHALLENGE_POINT_TYPE_ID) { - this.prizeType.description = "Challenge Points"; + } else if (prizeType == CHALLENGE_POINT_TYPE_ID) { + this.prizeType.description = "Challenge Points"; } this.numberOfSubmissions = numberOfSubmissions; @@ -211,35 +211,35 @@ var CODE_REPO = "Code Repo"; var MM_TYPE = "Marathon Match Type"; var projectCategoryArray = [ + {id:32, name:'Application Front-End Design', label:'Application Front-End Design', typeId:3, typeName:'Studio', hasMulti:true, hideInDropdown: false}, + {id:STUDIO_CATEGORY_ID_DESIGN_F2F, name:'Design First2Finish', label:'Design First2Finish', typeId:3, typeName:'Studio', hasMulti:false, hideInDropdown: false}, + {id:22, name:'Idea Generation', label:'Idea Generation', typeId:3, typeName:'Studio', hasMulti:true, hideInDropdown: false}, + {id:21, name:'Print/Presentation', label:'Print/Presentation', typeId:3, typeName:'Studio', hasMulti:true, hideInDropdown: false}, + {id:17, name:'Web Design', label:'Web Design', typeId:3, typeName:'Studio', hasMulti:true, hideInDropdown: false}, + {id:30, name:'Widget or Mobile Screen Design', label:'Widget or Mobile Screen Design', typeId:3, typeName:'Studio', hasMulti:true, hideInDropdown: false}, + {id:18, name:'Wireframes', label:'Wireframes', typeId:3, typeName:'Studio', hasMulti:true, hideInDropdown: false}, + {id:SOFTWARE_CATEGORY_ID_BUG_HUNT, name:'Bug Hunt', label:'Bug Hunt', typeId:2, typeName:'Application', hasMulti:false, hideInDropdown: false}, + {id:SOFTWARE_CATEGORY_ID_CODE, name:'Code', label:'Code', typeId:2, typeName:'Application', hasMulti:false, hideInDropdown: false}, + {id:SOFTWARE_CATEGORY_ID_F2F, name:'First2Finish', label:'First2Finish', typeId:2, typeName:'Application', hasMulti:false, hideInDropdown: false}, + {id:13, name:'TESTSUITES', label:'Test Suites', typeId:2, typeName:'Application', hasMulti:true, hideInDropdown: false}, {id:SOFTWARE_CATEGORY_ID_CONCEPT, name:'CONCEPTUALIZATION', label:'Software Conceptualization', typeId:2, typeName:'Application', hasMulti:true, hideInDropdown: true}, {id:SOFTWARE_CATEGORY_ID_SPEC, name:'SPECIFICATION', label:'Software Specification', typeId:2, typeName:'Application', hasMulti:true, hideInDropdown: true}, - {id:7, name:'ARCHITECTURE', label:'Architecture', typeId:2, typeName:'Application', hasMulti:true, hideInDropdown: false}, + {id:7, name:'ARCHITECTURE', label:'Architecture', typeId:2, typeName:'Application', hasMulti:true, hideInDropdown: true}, {id:SOFTWARE_CATEGORY_ID_DESIGN, name:'DESIGN', label:'Component Design', typeId:1, typeName:'Component', hasMulti:false, hideInDropdown: true}, {id:SOFTWARE_CATEGORY_ID_DEVELOPMENT, name:'DEVELOPMENT', label:'Component Development', typeId:1, typeName:'Component', hasMulti:false, hideInDropdown: true}, {id:25, name:'RIACOMPONENT', label:'RIA Component', typeId:2, typeName:'Application', hasMulti:true, hideInDropdown: true}, {id:24, name:'RIABUILD', label:'RIA Build', typeId:2, typeName:'Application', hasMulti:true, hideInDropdown: true}, - {id:19, name:'UIPROTOTYPE', label:'UI Prototype', typeId:2, typeName:'Application', hasMulti:true, hideInDropdown: false}, - {id:SOFTWARE_CATEGORY_ID_ASSEMBLY, name:'SOFTWARE ASSEMBLY', label:'Software Assembly', typeId:2, typeName:'Application', hasMulti:true, hideInDropdown: false}, - {id:13, name:'TESTSUITES', label:'Test Suites', typeId:2, typeName:'Application', hasMulti:true, hideInDropdown: false}, + {id:19, name:'UIPROTOTYPE', label:'UI Prototype', typeId:2, typeName:'Application', hasMulti:true, hideInDropdown: true}, + {id:SOFTWARE_CATEGORY_ID_ASSEMBLY, name:'SOFTWARE ASSEMBLY', label:'Software Assembly', typeId:2, typeName:'Application', hasMulti:true, hideInDropdown: true}, {id:26, name:'TESTSCENARIOS', label:'Test Scenarios', typeId:2, typeName:'Application', hasMulti:true, hideInDropdown: true}, {id:COPILOT_POSTING, name:'Copilot Posting', label:'Copilot Posting', typeId:2, typeName:'Application', hasMulti:false, hideInDropdown: true}, {id:SOFTWARE_CATEGORY_ID_CONTENT, name:'Content Creation', label:'Content Creation', typeId:2, typeName:'Application', hasMulti:true, hideInDropdown: true}, - {id:17, name:'Web Design', label:'Web Design', typeId:3, typeName:'Studio', hasMulti:true, hideInDropdown: false}, - {id:STUDIO_CATEGORY_ID_DESIGN_F2F, name:'Design First2Finish', label:'Design First2Finish', typeId:3, typeName:'Studio', hasMulti:false, hideInDropdown: false}, {id:20, name:'Logo Design', label:'Logo Design', typeId:3, typeName:'Studio', hasMulti:true, hideInDropdown: true}, {id:16, name:'Banners/Icons', label:'Banners/Icons', typeId:3, typeName:'Studio', hasMulti:true, hideInDropdown: true}, - {id:32, name:'Application Front-End Design', label:'Application Front-End Design', typeId:3, typeName:'Studio', hasMulti:true, hideInDropdown: false}, - {id:30, name:'Widget or Mobile Screen Design', label:'Widget or Mobile Screen Design', typeId:3, typeName:'Studio', hasMulti:true, hideInDropdown: false}, {id:31, name:'Front-End Flash', label:'Front-End Flash', typeId:3, typeName:'Studio', hasMulti:true, hideInDropdown: true}, - {id:21, name:'Print/Presentation', label:'Print/Presentation', typeId:3, typeName:'Studio', hasMulti:true, hideInDropdown: false}, {id:34, name:'Studio Other', label:'Studio Other', typeId:3, typeName:'Studio', hasMulti:true, hideInDropdown: true}, - {id:18, name:'Wireframes', label:'Wireframes', typeId:3, typeName:'Studio', hasMulti:true, hideInDropdown: false}, - {id:22, name:'Idea Generation', label:'Idea Generation', typeId:3, typeName:'Studio', hasMulti:true, hideInDropdown: false}, {id:36, name:'REPORTING', label:'Reporting', typeId:2, typeName:'Application', hasMulti:true, hideInDropdown: true}, - {id:ALGORITHM_CATEGORY_ID_MARATHON, name:'Marathon Match', label:'Marathon Match', typeId:2, typeName:'Application', hasMulti:false, hideInDropdown: false}, - {id:SOFTWARE_CATEGORY_ID_BUG_HUNT, name:'Bug Hunt', label:'Bug Hunt', typeId:2, typeName:'Application', hasMulti:false, hideInDropdown: false}, - {id:SOFTWARE_CATEGORY_ID_F2F, name:'First2Finish', label:'First2Finish', typeId:2, typeName:'Application', hasMulti:false, hideInDropdown: false}, - {id:SOFTWARE_CATEGORY_ID_CODE, name:'Code', label:'Code', typeId:2, typeName:'Application', hasMulti:false, hideInDropdown: false} + {id:ALGORITHM_CATEGORY_ID_MARATHON, name:'Marathon Match', label:'Marathon Match', typeId:2, typeName:'Application', hasMulti:false, hideInDropdown: false} ]; /** diff --git a/token.properties.docker b/token.properties.docker index b99e13589..997f94d93 100644 --- a/token.properties.docker +++ b/token.properties.docker @@ -64,7 +64,8 @@ ############################################################################################ # file storage location for DefaultUploadExternalServices in onlineReviewUpload_config.xml # ############################################################################################ -@file_storage_location@=/root/temp_files +@file_storage_location@=/root/submission_dev +@studio_file_storage_location@=/root/submission_design ############## # struts.xml # @@ -340,3 +341,7 @@ @directChallengeServicesApiUrl@=http://api.topcoder-dev.com/v3/direct/challenges @authorizationUrl@=https://api.topcoder-dev.com/v3/authorizations @userGroupsApiEndpoint@=http://tc-api.cloud.topcoder.com:8080/v3/groups + +@aws_s3_bucket@=topcoder-dev-submissions +@aws_s3_access_key@= +@aws_s3_secret_key@= diff --git a/topcoder_global.properties b/topcoder_global.properties index a4a29bbd6..c0445053b 100644 --- a/topcoder_global.properties +++ b/topcoder_global.properties @@ -14,4 +14,3 @@ server.name=default jboss.config.name=${server.name} jboss_config_name=${server.name} jboss_lib=${jboss.home}/server/${server.name}/lib -