Package com.dotcms.publisher.ajax

Source Code of com.dotcms.publisher.ajax.RemotePublishAjaxAction

package com.dotcms.publisher.ajax;

import com.dotcms.publisher.bundle.bean.Bundle;
import com.dotcms.publisher.business.*;
import com.dotcms.publisher.business.PublishAuditStatus.Status;
import com.dotcms.publisher.business.PublisherAPI;
import com.dotcms.publisher.endpoint.bean.PublishingEndPoint;
import com.dotcms.publisher.environment.bean.Environment;
import com.dotcms.publisher.pusher.PushPublisher;
import com.dotcms.publisher.pusher.PushPublisherConfig;
import com.dotcms.publisher.pusher.PushUtils;
import com.dotcms.publisher.util.PublisherUtil;
import com.dotcms.publishing.*;
import com.dotcms.rest.PublishThread;
import com.dotmarketing.beans.Identifier;
import com.dotmarketing.beans.Inode;
import com.dotmarketing.business.APILocator;
import com.dotmarketing.business.DotStateException;
import com.dotmarketing.business.PermissionAPI;
import com.dotmarketing.cms.login.factories.LoginFactory;
import com.dotmarketing.exception.DotDataException;
import com.dotmarketing.exception.DotRuntimeException;
import com.dotmarketing.exception.DotSecurityException;
import com.dotmarketing.portlets.folders.model.Folder;
import com.dotmarketing.portlets.workflows.model.WorkflowActionFailureException;
import com.dotmarketing.servlets.ajax.AjaxAction;
import com.dotmarketing.util.*;
import com.dotmarketing.util.json.JSONArray;
import com.dotmarketing.util.json.JSONObject;
import com.liferay.portal.language.LanguageException;
import com.liferay.portal.language.LanguageUtil;
import com.liferay.portal.model.User;
import com.dotcms.repackage.org.apache.commons.fileupload.FileItem;
import com.dotcms.repackage.org.apache.commons.fileupload.FileItemFactory;
import com.dotcms.repackage.org.apache.commons.fileupload.FileUploadException;
import com.dotcms.repackage.org.apache.commons.fileupload.disk.DiskFileItemFactory;
import com.dotcms.repackage.org.apache.commons.fileupload.servlet.ServletFileUpload;
import com.dotcms.repackage.org.apache.commons.httpclient.HttpStatus;
import com.dotcms.repackage.org.apache.commons.io.FileUtils;
import com.dotcms.repackage.org.apache.hadoop.mapred.lib.Arrays;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.*;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public class RemotePublishAjaxAction extends AjaxAction {

  public static final String DIALOG_ACTION_EXPIRE="expire";
  public static final String DIALOG_ACTION_PUBLISH="publish";
  public static final String DIALOG_ACTION_PUBLISH_AND_EXPIRE="publishexpire";

  @Override
  public void action(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    return;
  }

  @Override
  public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    Map<String, String> map = getURIParams();
    String cmd = map.get( "cmd" );
    Method dispatchMethod = null;

    User user = getUser();

    try{
      // Check permissions if the user has access to the CMS Maintenance Portlet
      if (user == null) {
        String userName = map.get("u") !=null
          ? map.get("u")
            : map.get("user") !=null
              ? map.get("user")
                : null;

        String password = map.get("p") !=null
          ? map.get("p")
              : map.get("passwd") !=null
                ? map.get("passwd")
                  : null;



        LoginFactory.doLogin(userName, password, false, request, response);
        user = (User) request.getSession().getAttribute(WebKeys.CMS_USER);
                //Set the logged user in order to make it available from this action using the getUser() method
                if ( user != null ) {
                    setUser( user );
                }

        if(user==null) {
            setUser(request);
                  user = getUser();
        }
        if(user==null){
          response.sendError(401);
          return;
        }
      }
    }
    catch(Exception e){
      Logger.error(this.getClass(), e.getMessage());
      response.sendError(401);
      return;
    }

    if(null!=cmd){
      try {
        dispatchMethod = this.getClass().getMethod(cmd, new Class[]{HttpServletRequest.class, HttpServletResponse.class});
      } catch (Exception e) {
        try {
          dispatchMethod = this.getClass().getMethod("action", new Class[]{HttpServletRequest.class, HttpServletResponse.class});
        } catch (Exception e1) {
          Logger.error(this.getClass(), "Trying to get method:" + cmd);
          Logger.error(this.getClass(), e1.getMessage(), e1.getCause());
          throw new DotRuntimeException(e1.getMessage());
        }
      }
      try {
        dispatchMethod.invoke(this, new Object[]{request,response});
      } catch (Exception e) {
        Logger.error(this.getClass(), "Trying to invoke method:" + cmd);
        Logger.error(this.getClass(), e.getMessage(), e.getCause());
        throw new DotRuntimeException(e.getMessage());
      }
    }

  }

    /**
     * Send to the publisher queue a list of assets for a given Operation (Publish/Unpublish) and {@link Environment Environment}
     *
     * @param request  HttpRequest
     * @param response HttpResponse
     * @throws WorkflowActionFailureException If fails adding the content for Publish
     * @see com.dotcms.publisher.business.PublisherQueueJob
     * @see Environment
     */
    public void publish ( HttpServletRequest request, HttpServletResponse response ) throws IOException, WorkflowActionFailureException {

        try {

            PublisherAPI publisherAPI = PublisherAPI.getInstance();

            //Read the form values
            String _assetId = request.getParameter( "assetIdentifier" );
            String _contentPushPublishDate = request.getParameter( "remotePublishDate" );
            String _contentPushPublishTime = request.getParameter( "remotePublishTime" );
            String _contentPushExpireDate = request.getParameter( "remotePublishExpireDate" );
            String _contentPushExpireTime = request.getParameter( "remotePublishExpireTime" );
            String _contentFilterDate = request.getParameter( "remoteFilterDate" );
            String _iWantTo = request.getParameter( "iWantTo" );
            String whoToSendTmp = request.getParameter( "whoToSend" );
            String forcePushStr = request.getParameter( "forcePush" );
            boolean forcePush = (forcePushStr!=null && forcePushStr.equals("true"));
            List<String> whereToSend = Arrays.asList(whoToSendTmp.split(","));
            List<Environment> envsToSendTo = new ArrayList<Environment>();

            // Lists of Environments to push to
            for (String envId : whereToSend) {
              Environment e = APILocator.getEnvironmentAPI().findEnvironmentById(envId);

              if(e!=null) {
                envsToSendTo.add(e);
              }
      }

            //Put the selected environments in session in order to have the list of the last selected environments
            request.getSession().setAttribute( WebKeys.SELECTED_ENVIRONMENTS + getUser().getUserId(), envsToSendTo );

            SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy-MM-dd-H-m" );
            Date publishDate = dateFormat.parse( _contentPushPublishDate + "-" + _contentPushPublishTime );

            List<String> ids;
            if ( _assetId.startsWith( "query_" ) ) { //Support for lucene queries

                String luceneQuery = _assetId.replace( "query_", "" );
                List<String> queries = new ArrayList<String>();
                queries.add( luceneQuery );
                ids = PublisherUtil.getContentIds( queries );

            } else {

                String[] _assetsIds = _assetId.split( "," );//Support for multiple ids in the assetIdentifier parameter
                List<String> assetsIds = Arrays.asList( _assetsIds );

                ids = getIdsToPush( assetsIds, null, _contentFilterDate, dateFormat );
            }

            //Response map with the status of the addContents operation (error messages and counts )
            Map<String, Object> responseMap = null;

            if ( _iWantTo.equals( RemotePublishAjaxAction.DIALOG_ACTION_PUBLISH ) || _iWantTo.equals( RemotePublishAjaxAction.DIALOG_ACTION_PUBLISH_AND_EXPIRE ) ) {
              Bundle bundle = new Bundle(null, publishDate, null, getUser().getUserId(), forcePush);
              APILocator.getBundleAPI().saveBundle(bundle, envsToSendTo);

                responseMap = publisherAPI.addContentsToPublish( ids, bundle.getId(), publishDate, getUser() );
            }
            if ( _iWantTo.equals( RemotePublishAjaxAction.DIALOG_ACTION_EXPIRE ) || _iWantTo.equals( RemotePublishAjaxAction.DIALOG_ACTION_PUBLISH_AND_EXPIRE ) ) {
                if ( (!"".equals( _contentPushExpireDate.trim() ) && !"".equals( _contentPushExpireTime.trim() )) ) {
                    Date expireDate = dateFormat.parse( _contentPushExpireDate + "-" + _contentPushExpireTime );

                    Bundle bundle = new Bundle(null, publishDate, expireDate, getUser().getUserId(), forcePush);
                  APILocator.getBundleAPI().saveBundle(bundle, envsToSendTo);

                    responseMap = publisherAPI.addContentsToUnpublish( ids, bundle.getId(), expireDate, getUser() );
                }
            }

            //If we have errors lets return them in order to feedback the user
            if ( responseMap != null && !responseMap.isEmpty() ) {

                //Error messages
                JSONArray jsonErrors = new JSONArray( (ArrayList) responseMap.get( "errorMessages" ) );

                //Prepare the Json response
                JSONObject jsonResponse = new JSONObject();
                jsonResponse.put( "errorMessages", jsonErrors.toArray() );
                jsonResponse.put( "errors", responseMap.get( "errors" ) );
                jsonResponse.put( "total", responseMap.get( "total" ) );
                jsonResponse.put( "bundleId", responseMap.get( "bundleId" ) );

                //And send it back to the user
                response.getWriter().println( jsonResponse.toString() );
            }
        } catch ( Exception e ) {
            Logger.error( RemotePublishAjaxAction.class, e.getMessage(), e );
            response.sendError( HttpStatus.SC_INTERNAL_SERVER_ERROR, "Error Publishing Bundle: " + e.getMessage() );
        }
    }

    /**
     * Allow the user to send or try to send again failed and successfully sent bundles, in order to do that<br/>
     * we send the bundle again to que publisher queue job which will try to remote publish again the bundle.
     * @param request  HttpRequest
     * @param response HttpResponse
     * @throws IOException If fails sending back to the user a proper response
     * @throws DotPublisherException If fails retrieving the Bundle related information like elements on it and statuses
     * @throws LanguageException If fails using i18 messages
     */
    public void retry ( HttpServletRequest request, HttpServletResponse response ) throws IOException, DotPublisherException, LanguageException {

        PublisherAPI publisherAPI = PublisherAPI.getInstance();
        PublishAuditAPI publishAuditAPI = PublishAuditAPI.getInstance();

        //Read the parameters
        String bundlesIds = request.getParameter( "bundlesIds" );
        String[] ids = bundlesIds.split( "," );

        StringBuilder responseMessage = new StringBuilder();

        for ( String bundleId : ids ) {

            if ( bundleId.trim().isEmpty() ) {
                continue;
            }

            PublisherConfig basicConfig = new PublisherConfig();
            basicConfig.setId( bundleId );
            File bundleRoot = BundlerUtil.getBundleRoot( basicConfig );

            //Get the audit records related to this bundle
            PublishAuditStatus status = PublishAuditAPI.getInstance().getPublishAuditStatus( bundleId );
            String pojo_string = status.getStatusPojo().getSerialized();
            PublishAuditHistory auditHistory = PublishAuditHistory.getObjectFromString( pojo_string );

            //First we need to verify is this bundle is already in the queue job
            List<PublishQueueElement> foundBundles = publisherAPI.getQueueElementsByBundleId( bundleId );
            if ( foundBundles != null && !foundBundles.isEmpty() ) {
                appendMessage( responseMessage, "publisher_retry.error.already.in.queue", bundleId, true );
                continue;
            }

            //We will be able to retry failed and successfully bundles
            if ( !(status.getStatus().equals( Status.FAILED_TO_PUBLISH ) || status.getStatus().equals( Status.SUCCESS )) ) {
                appendMessage( responseMessage, "publisher_retry.error.only.failed.publish", bundleId, true );
                continue;
            }

            /*
            Verify if the bundle exist and was created correctly..., meaning, if there is not a .tar.gz file is because
            something happened on the creation of the bundle.
             */
            File bundleFile = new File( bundleRoot + File.separator + ".." + File.separator + basicConfig.getId() + ".tar.gz" );
            if ( !bundleFile.exists() ) {
                Logger.error( this.getClass(), "No Bundle with id: " + bundleId + " found." );
                appendMessage( responseMessage, "publisher_retry.error.not.found", bundleId, true );
                continue;
            }

            if ( !BundlerUtil.bundleExists( basicConfig ) ) {
                Logger.error( this.getClass(), "No Bundle Descriptor for bundle id: " + bundleId + " found." );
                appendMessage( responseMessage, "publisher_retry.error.not.descriptor.found", bundleId, true );
                continue;
            }

            try {

                //Read the bundle to see what kind of configuration we need to apply
                String bundlePath = ConfigUtils.getBundlePath() + File.separator + basicConfig.getId();
                File xml = new File( bundlePath + File.separator + "bundle.xml" );
                PushPublisherConfig config = (PushPublisherConfig) BundlerUtil.xmlToObject( xml );

                //We can not retry Received Bundles, just bundles that we are trying to send
                Boolean sending = sendingBundle( request, config, bundleId );
                if ( !sending ) {
                    appendMessage( responseMessage, "publisher_retry.error.cannot.retry.received", bundleId, true );
                    continue;
                }

                if ( status.getStatus().equals( Status.SUCCESS ) ) {

                    //Get the bundle
                    Bundle bundle = APILocator.getBundleAPI().getBundleById( bundleId );
                    if ( bundle == null ) {
                        Logger.error( this.getClass(), "No Bundle with id: " + bundleId + " found." );
                        appendMessage( responseMessage, "publisher_retry.error.not.found", bundleId, true );
                        continue;
                    }
                    bundle.setForcePush( true );
                    APILocator.getBundleAPI().updateBundle( bundle );
                }

                //Clean the number of tries, we want to try it again
                auditHistory.setNumTries( 0 );
                publishAuditAPI.updatePublishAuditStatus( config.getId(), status.getStatus(), auditHistory, true );

                //Get the identifiers on this bundle
                HashSet<String> identifiers = new HashSet<String>();
                List<PublishQueueElement> assets = config.getAssets();
                if ( config.getLuceneQueries() != null && !config.getLuceneQueries().isEmpty() ) {
                    identifiers.addAll( PublisherUtil.getContentIds( config.getLuceneQueries() ) );
                }
                if ( assets != null && !assets.isEmpty() ) {
                    for ( PublishQueueElement asset : assets ) {
                        identifiers.add( asset.getAsset() );
                    }
                }

                //Cleaning previous bundle folder and tar file to avoid sending modified data
                FileUtils.cleanDirectory(new File(bundlePath));
                bundleFile.delete();
               
                //Now depending of the operation lets add it to the queue job
                if ( config.getOperation().equals( PushPublisherConfig.Operation.PUBLISH ) ) {
                    publisherAPI.addContentsToPublish( new ArrayList<String>( identifiers ), bundleId, new Date(), getUser() );
                } else {
                    publisherAPI.addContentsToUnpublish( new ArrayList<String>( identifiers ), bundleId, new Date(), getUser() );
                }

                //Success...
                appendMessage( responseMessage, "publisher_retry.success", bundleId, false );
            } catch ( Exception e ) {
                Logger.error( this.getClass(), "Error trying to add bundle id: " + bundleId + " to the Publishing Queue.", e );
                appendMessage( responseMessage, "publisher_retry.error.adding.to.queue", bundleId, true );
            }
        }

        response.getWriter().println( responseMessage.toString() );
    }

    /**
     * Downloads a Bundle file for a given bundle id.
     *
     * @param request  HttpRequest
     * @param response HttpResponse
     * @throws IOException If fails sending back to the user response information
     */
    public void downloadBundle ( HttpServletRequest request, HttpServletResponse response ) throws IOException {
      try {
      if(!APILocator.getLayoutAPI().doesUserHaveAccessToPortlet("EXT_CONTENT_PUBLISHING_TOOL", getUser())){
        response.sendError(401);
        return;
      }
    } catch (DotDataException e1) {
      Logger.error(RemotePublishAjaxAction.class,e1.getMessage(),e1);
      response.sendError(401);
      return;
    }
        Map<String, String> map = getURIParams();
        response.setContentType( "application/x-tgz" );

        String bid = map.get( "bid" );

        PublisherConfig config = new PublisherConfig();
        config.setId( bid );
        File bundleRoot = BundlerUtil.getBundleRoot( config );

        ArrayList<File> list = new ArrayList<File>( 1 );
        list.add( bundleRoot );
        File bundle = new File( bundleRoot + File.separator + ".." + File.separator + config.getId() + ".tar.gz" );
        if ( !bundle.exists() ) {
            response.sendError( 500, "No Bundle Found" );
            return;
        }

        response.setHeader( "Content-Disposition", "attachment; filename=" + config.getId() + ".tar.gz" );
        BufferedInputStream in = null;
        try {
            in = new BufferedInputStream( new FileInputStream( bundle ) );
            byte[] buf = new byte[4096];
            int len;

            while ( (len = in.read( buf, 0, buf.length )) != -1 ) {
                response.getOutputStream().write( buf, 0, len );
            }
        } catch ( Exception e ) {
            Logger.warn( this.getClass(), "Error Downloading Bundle.", e );
        } finally {
            try {
                in.close();
            } catch ( Exception ex ) {
                Logger.warn( this.getClass(), "Error Closing Stream.", ex );
            }
        }
        return;
    }

    /**
     * Generates and flush an Unpublish bundle for a given bundle id and operation (publish/unpublish)
     *
     * @param request  HttpRequest
     * @param response HttpResponse
     * @throws IOException If fails sending back to the user response information
     */
    public void downloadUnpushedBundle ( HttpServletRequest request, HttpServletResponse response ) throws IOException {
      try {
      if(!APILocator.getLayoutAPI().doesUserHaveAccessToPortlet("EXT_CONTENT_PUBLISHING_TOOL", getUser())){
        response.sendError(401);
        return;
      }
    } catch (DotDataException e1) {
      Logger.error(RemotePublishAjaxAction.class,e1.getMessage(),e1);
      response.sendError(401);
      return;
    }
        //Read the parameters
        Map<String, String> map = getURIParams();
        String bundleId = map.get( "bundleId" );
        String paramOperation = map.get( "operation" );
        if ( bundleId == null || bundleId.isEmpty() ) {
            Logger.error( this.getClass(), "No Bundle Found with id: " + bundleId );
            response.sendError( 500, "No Bundle Found with id: " + bundleId );
            return;
        }

        //What we want to do with this bundle
        PushPublisherConfig.Operation operation = PushPublisherConfig.Operation.PUBLISH;
        if ( paramOperation != null && paramOperation.equalsIgnoreCase( "unpublish" ) ) {
            operation = PushPublisherConfig.Operation.UNPUBLISH;
        }

        File bundle;
        String generatedBundleId;
        try {
            //Generate the bundle file for this given operation
            Map<String, Object> bundleData = generateBundle( bundleId, operation );
            bundle = (File) bundleData.get( "file" );
            generatedBundleId = (String) bundleData.get( "id" );
        } catch ( Exception e ) {
            Logger.error( this.getClass(), "Error trying to generate bundle with id: " + bundleId, e );
            response.sendError( 500, "Error trying to generate bundle with id: " + bundleId );
            return;
        }

        response.setContentType( "application/x-tgz" );
        response.setHeader( "Content-Disposition", "attachment; filename=" + bundle.getName() );
        BufferedInputStream in = null;
        try {
            in = new BufferedInputStream( new FileInputStream( bundle ) );
            byte[] buf = new byte[4096];
            int len;

            while ( (len = in.read( buf, 0, buf.length )) != -1 ) {
                response.getOutputStream().write( buf, 0, len );
            }
        } catch ( Exception e ) {
            Logger.error( this.getClass(), "Error reading bundle stream for bundle id: " + bundleId, e );
            response.sendError( 500, "Error reading bundle stream for bundle id: " + bundleId );
        } finally {
            try {
                in.close();
            } catch ( Exception ex ) {
                Logger.error( this.getClass(), "Error closing Stream for bundle: " + bundleId, ex );
            }

            //Clean the just created bundle because on each download we will generate a new bundle file with a new id in order to avoid conflicts with ids
            File bundleRoot = BundlerUtil.getBundleRoot( generatedBundleId );
            File compressedBundle = new File( ConfigUtils.getBundlePath() + File.separator + generatedBundleId + ".tar.gz" );
            if ( compressedBundle.exists() ) {
                compressedBundle.delete();
                if ( bundleRoot.exists() ) {
                    com.liferay.util.FileUtil.deltree( bundleRoot );
                }
            }
        }
    }

    /**
     * Generates an Unpublish bundle for a given bundle id  operation (publish/unpublish)
     *
     * @param bundleId The Bundle id of the Bundle we want to generate
     * @param operation Download for publish or un-publish
     * @return The generated requested Bundle file
     * @throws DotPublisherException If fails retrieving the Bundle contents
     * @throws DotDataException If fails finding the system user
     * @throws DotPublishingException If fails initializing the Publisher
     * @throws IllegalAccessException If fails creating new Bundlers instances
     * @throws InstantiationException If fails creating new Bundlers instances
     * @throws DotBundleException If fails generating the Bundle
     * @throws IOException If fails compressing the all the Bundle contents into the final Bundle file
     */
    @SuppressWarnings ("unchecked")
    private Map<String, Object> generateBundle ( String bundleId, PushPublisherConfig.Operation operation ) throws DotPublisherException, DotDataException, DotPublishingException, IllegalAccessException, InstantiationException, DotBundleException, IOException {

        PushPublisherConfig pconf = new PushPublisherConfig();
        PublisherAPI pubAPI = PublisherAPI.getInstance();

        List<PublishQueueElement> tempBundleContents = pubAPI.getQueueElementsByBundleId( bundleId );
        List<PublishQueueElement> assetsToPublish = new ArrayList<PublishQueueElement>(); // all assets but contentlets

        for ( PublishQueueElement c : tempBundleContents ) {
            if ( !c.getType().equals( "contentlet" ) ) {
                assetsToPublish.add( c );
            }
        }

        pconf.setDownloading( true );
        pconf.setOperation(operation);

        // all types of assets in the queue but contentlets are passed here, which are passed through lucene queries
        pconf.setAssets( assetsToPublish );
        //Queries creation
        pconf.setLuceneQueries( PublisherUtil.prepareQueries( tempBundleContents ) );
        pconf.setId( bundleId );
        pconf.setUser( APILocator.getUserAPI().getSystemUser() );

        //BUNDLERS

        List<Class<IBundler>> bundlers = new ArrayList<Class<IBundler>>();
        List<IBundler> confBundlers = new ArrayList<IBundler>();

        Publisher publisher = new PushPublisher();
        publisher.init( pconf );
        //Add the bundles for this publisher
        for ( Class clazz : publisher.getBundlers() ) {
            if ( !bundlers.contains( clazz ) ) {
                bundlers.add( clazz );
            }
        }

        //Create a new bundle id for this generated bundle
        String newBundleId = UUID.randomUUID().toString();
        pconf.setId( newBundleId );
        File bundleRoot = BundlerUtil.getBundleRoot( pconf );

        // Run bundlers
        BundlerUtil.writeBundleXML( pconf );
        for ( Class<IBundler> c : bundlers ) {

            IBundler bundler = c.newInstance();
            confBundlers.add( bundler );
            bundler.setConfig( pconf );
            BundlerStatus bundlerStatus = new BundlerStatus( bundler.getClass().getName() );
            //Generate the bundler
            bundler.generate( bundleRoot, bundlerStatus );
        }

        pconf.setBundlers( confBundlers );

        //Compressing bundle
        ArrayList<File> list = new ArrayList<File>();
        list.add( bundleRoot );
        File bundle = new File( bundleRoot + File.separator + ".." + File.separator + pconf.getId() + ".tar.gz" );

        Map<String, Object> bundleData = new HashMap<String, Object>();
        bundleData.put( "id", newBundleId );
        bundleData.put( "file", PushUtils.compressFiles( list, bundle, bundleRoot.getAbsolutePath() ) );
        return bundleData;
    }

    /**
     * Publish a given Bundle file
     *
     * @param request  HttpRequest
     * @param response HttpResponse
     * @throws FileUploadException If fails uploading the file
     * @throws IOException         If fails reading the given File content or sending back to the user a response
     */
    public void uploadBundle ( HttpServletRequest request, HttpServletResponse response ) throws FileUploadException, IOException{

      try {
      if(!APILocator.getLayoutAPI().doesUserHaveAccessToPortlet("EXT_CONTENT_PUBLISHING_TOOL", getUser())){
        response.sendError(401);
        return;
      }
    } catch (DotDataException e1) {
      Logger.error(RemotePublishAjaxAction.class,e1.getMessage(),e1);
      response.sendError(401);
      return;
    }

        FileItemFactory factory = new DiskFileItemFactory();
        ServletFileUpload upload = new ServletFileUpload( factory );
        @SuppressWarnings ("unchecked")
        List<FileItem> items = (List<FileItem>) upload.parseRequest( request );

        InputStream bundle = items.get( 0 ).getInputStream();
        String bundleName = items.get( 0 ).getName();
        String bundlePath = ConfigUtils.getBundlePath() + File.separator;
        String bundleFolder = bundleName.substring( 0, bundleName.indexOf( ".tar.gz" ) );
        String endpointId = getUser().getUserId();
        response.setContentType( "text/html; charset=utf-8" );
        PrintWriter out = response.getWriter();

        PublishAuditStatus status;
        try {
            status = PublishAuditAPI.getInstance().updateAuditTable( endpointId, endpointId, bundleFolder );

            // Write file on FS
            FileUtil.writeToFile( bundle, bundlePath + bundleName );

            if ( !status.getStatus().equals( Status.PUBLISHING_BUNDLE ) ) {
                new Thread( new PublishThread( bundleName, null, endpointId, status ) ).start();
            }

            out.print( "<html><head><script>isLoaded = true;</script></head><body><textarea>{'status':'success'}</textarea></body></html>" );

        } catch ( DotPublisherException e ) {
            // TODO Auto-generated catch block
            out.print( "<html><head><script>isLoaded = true;</script></head><body><textarea>{'status':'error'}</textarea></body></html>" );
        }

    }

    /**
     * Appends info messages to a main StringBuilder message for an easier display to the user
     *
     * @param responseMessage Response message to return to the user
     * @param messageKey      i18 key
     * @param bundleId        Current bundle
     * @param failure         True for failures, false otherwise
     * @throws LanguageException If fails using the i18 massage key
     */
    private void appendMessage ( StringBuilder responseMessage, String messageKey, String bundleId, Boolean failure ) throws LanguageException {

        String message = LanguageUtil.format( getUser().getLocale(), messageKey, new String[]{bundleId}, false );
        if ( responseMessage.length() > 0 ) {
            responseMessage.append( "<br>" );
        }
        if ( failure ) {
            responseMessage.append( "FAILURE: " ).append( message );
        } else {
            responseMessage.append( message );
        }
    }

    /**
     * Verifies what we were doing to the current bundle, it was received for this server?, or this server is trying to send it....,
     * we don't want to retry bundles we received.
     *
     * @param request
     * @param config
     * @return
     */
    private Boolean sendingBundle ( HttpServletRequest request, PushPublisherConfig config, String bundleId ) throws DotDataException {

        //Get the local address
        String remoteIP = request.getRemoteHost();
        int port = request.getLocalPort();
        if ( !UtilMethods.isSet( remoteIP ) ) {
            remoteIP = request.getRemoteAddr();
        }

        /*
         Getting the bundle end points in order to compare if this current server it is an end point or not.
         If it is is because we received this bundle as we were a targeted end point server.
         */

        List<Environment> environments = APILocator.getEnvironmentAPI().findEnvironmentsByBundleId(bundleId);

        for (Environment environment : environments) {

          List<PublishingEndPoint> endPoints = APILocator.getPublisherEndPointAPI().findSendingEndPointsByEnvironment(environment.getId());
          for ( PublishingEndPoint endPoint : endPoints ) {

              //Getting the end point details
              String endPointAddress = endPoint.getAddress();
              String endPointPort = endPoint.getPort();

              if ( endPointAddress.equals( remoteIP )
                      && endPointPort.equals( String.valueOf( port ) ) ) {
                  return false;
              }
          }
        }

        return true;
    }

    /**
     * Adds to an specific given bundle a given asset.
     * <br/>If the given bundle does not exist a new onw will be created with that name
     *
     * @param request  HttpRequest
     * @param response HttpResponse
     */
    public void addToBundle ( HttpServletRequest request, HttpServletResponse response ) throws IOException {

        PublisherAPI publisherAPI = PublisherAPI.getInstance();
        String _assetId = request.getParameter( "assetIdentifier" );
        String _contentFilterDate = request.getParameter( "remoteFilterDate" );
        String bundleName = request.getParameter( "bundleName" );
        String bundleId = request.getParameter( "bundleSelect" );

        try {
            Bundle bundle;

            if ( bundleId == null || bundleName.equals( bundleId ) ) {
                // if the user has a unsent bundle with that name just add to it
                bundle=null;
                for(Bundle b : APILocator.getBundleAPI().getUnsendBundlesByName(getUser().getUserId(), bundleName, 1000, 0)) {
                    if(b.getName().equalsIgnoreCase(bundleName)) {
                        bundle=b;
                    }
                }

                if(bundle==null) {
                    bundle = new Bundle( bundleName, null, null, getUser().getUserId() );
                    APILocator.getBundleAPI().saveBundle( bundle );
                }
            } else {
                bundle = APILocator.getBundleAPI().getBundleById( bundleId );
            }

            //Put the selected bundle in session in order to have last one selected
            request.getSession().setAttribute( WebKeys.SELECTED_BUNDLE + getUser().getUserId(), bundle );

            List<String> ids;
            if ( _assetId.startsWith( "query_" ) ) { //Support for lucene queries

                String luceneQuery = _assetId.replace( "query_", "" );
                List<String> queries = new ArrayList<String>();
                queries.add( luceneQuery );
                ids = PublisherUtil.getContentIds( queries );

            } else {

                String[] _assetsIds = _assetId.split( "," );//Support for multiple ids in the assetIdentifier parameter
                List<String> assetsIds = Arrays.asList( _assetsIds );

                ids = getIdsToPush( assetsIds,bundle.getId(), _contentFilterDate, new SimpleDateFormat( "yyyy-MM-dd-H-m" ) );
            }

            Map<String, Object> responseMap = publisherAPI.saveBundleAssets( ids, bundle.getId(), getUser() );

            //If we have errors lets return them in order to feedback the user
            if ( responseMap != null && !responseMap.isEmpty() ) {

                //Error messages
                JSONArray jsonErrors = new JSONArray( (ArrayList) responseMap.get( "errorMessages" ) );

                //Prepare the Json response
                JSONObject jsonResponse = new JSONObject();
                jsonResponse.put( "errorMessages", jsonErrors.toArray() );
                jsonResponse.put( "errors", responseMap.get( "errors" ) );
                jsonResponse.put( "total", responseMap.get( "total" ) );

                //And send it back to the user
                response.getWriter().println( jsonResponse.toString() );
            }
        } catch ( Exception e ) {
            Logger.error( RemotePublishAjaxAction.class, e.getMessage(), e );
            response.sendError( HttpStatus.SC_INTERNAL_SERVER_ERROR, "Error Adding content to Bundle: " + e.getMessage() );
        }
    }

    /**
     * Updates the assets in the given bundle with the publish/expire dates and destination environments and set them ready to be pushed
     *
     * @param request  HttpRequest
     * @param response HttpResponse
     * @throws WorkflowActionFailureException If fails trying to Publish the bundle contents
     */
    public void pushBundle ( HttpServletRequest request, HttpServletResponse response ) throws WorkflowActionFailureException, IOException {
        response.setContentType("text/plain");
        try {

            PublisherAPI publisherAPI = PublisherAPI.getInstance();

            //Read the form values
            String bundleId = request.getParameter( "assetIdentifier" );
            String _contentPushPublishDate = request.getParameter( "remotePublishDate" );
            String _contentPushPublishTime = request.getParameter( "remotePublishTime" );
            String _contentPushExpireDate = request.getParameter( "remotePublishExpireDate" );
            String _contentPushExpireTime = request.getParameter( "remotePublishExpireTime" );
            String _iWantTo = request.getParameter( "iWantTo" );
            String whoToSendTmp = request.getParameter( "whoToSend" );
            List<String> whereToSend = Arrays.asList(whoToSendTmp.split(","));
            List<Environment> envsToSendTo = new ArrayList<Environment>();

            // Lists of Environments to push to
            for (String envId : whereToSend) {
              Environment e = APILocator.getEnvironmentAPI().findEnvironmentById(envId);

              if(e!=null && APILocator.getPermissionAPI().doesUserHavePermission(e, PermissionAPI.PERMISSION_USE, getUser())) {
                envsToSendTo.add(e);
              }
      }

            if(envsToSendTo.isEmpty()) {
                response.sendError(HttpServletResponse.SC_FORBIDDEN);
                return;
            }

            //Put the selected environments in session in order to have the list of the last selected environments
            request.getSession().setAttribute( WebKeys.SELECTED_ENVIRONMENTS + getUser().getUserId(), envsToSendTo );
            //Clean up the selected bundle
            request.getSession().removeAttribute( WebKeys.SELECTED_BUNDLE + getUser().getUserId() );

            SimpleDateFormat dateFormat = new SimpleDateFormat( "yyyy-MM-dd-H-m" );
            Date publishDate = dateFormat.parse( _contentPushPublishDate + "-" + _contentPushPublishTime );
            Bundle bundle = APILocator.getBundleAPI().getBundleById(bundleId);
            APILocator.getBundleAPI().saveBundleEnvironments(bundle, envsToSendTo);

            if ( _iWantTo.equals( RemotePublishAjaxAction.DIALOG_ACTION_PUBLISH )) {
              bundle.setPublishDate(publishDate);
               APILocator.getBundleAPI().updateBundle(bundle);

               publisherAPI.publishBundleAssets(bundle.getId(), publishDate);

            } else if ( _iWantTo.equals( RemotePublishAjaxAction.DIALOG_ACTION_EXPIRE )) {
              if ( (!"".equals( _contentPushExpireDate.trim() ) && !"".equals( _contentPushExpireTime.trim() )) ) {
                    Date expireDate = dateFormat.parse( _contentPushExpireDate + "-" + _contentPushExpireTime );
                    bundle.setExpireDate(expireDate);
                  APILocator.getBundleAPI().updateBundle(bundle);

                  publisherAPI.unpublishBundleAssets(bundle.getId(), expireDate);
                }

            } else if(_iWantTo.equals( RemotePublishAjaxAction.DIALOG_ACTION_PUBLISH_AND_EXPIRE ) ) {
                if ( (!"".equals( _contentPushExpireDate.trim() ) && !"".equals( _contentPushExpireTime.trim() )) ) {
                    Date expireDate = dateFormat.parse( _contentPushExpireDate + "-" + _contentPushExpireTime );
                    bundle.setPublishDate(publishDate);
                    bundle.setExpireDate(expireDate);
                  APILocator.getBundleAPI().updateBundle(bundle);

                  publisherAPI.publishAndExpireBundleAssets(bundle.getId(), publishDate, expireDate, getUser());
                }
            }

        } catch ( Exception e ) {
            Logger.error( RemotePublishAjaxAction.class, e.getMessage(), e );
            response.sendError( HttpStatus.SC_INTERNAL_SERVER_ERROR, "Error Push Publishing Bundle: " + e.getMessage() );
        }
    }

    /**
     * Returns the list of ids the user is trying to remote publish.
     */
    private List<String> getIdsToPush ( List<String> assetIds, String bundleId, String _contentFilterDate, SimpleDateFormat dateFormat )
            throws ParseException, DotDataException {

      List<String> ids = new ArrayList<String>();

        for ( String _assetId : assetIds ) {

            if ( _assetId != null && !_assetId.trim().isEmpty() ) {

                if ( ids.contains( _assetId ) ) {
                    continue;
                }

                // check for the categories
                if ( _assetId.contains( "user_" ) || _assetId.contains( "users_" ) ) {//Trying to publish users
                    //If we are trying to push users a filter date must be available
                    if ( _assetId.contains( "users_" ) ) {
                        Date filteringDate = dateFormat.parse( _contentFilterDate );
                        //Get users where createdate >= ?
                        List<String> usersIds = APILocator.getUserAPI().getUsersIdsByCreationDate( filteringDate, 0, -1 );
                        if ( usersIds != null ) {
                            for ( String id : usersIds ) {
                              if(!UtilMethods.isSet(bundleId) || !isAssetInBundle("user_" + id, bundleId)){
                                ids.add( "user_" + id );
                              }
                            }
                        }
                    } else {
                      if(!UtilMethods.isSet(bundleId) || !isAssetInBundle(_assetId, bundleId)){
                        ids.add( _assetId );
                      }
                    }
                } else if ( _assetId.equals( "CAT" ) ) {
                  if(!UtilMethods.isSet(bundleId) || !isAssetInBundle(_assetId, bundleId)){
                    ids.add( _assetId );
                  }
                } else if ( _assetId.contains( ".jar" ) ) {//Check for OSGI jar bundles
                  if(!UtilMethods.isSet(bundleId) || !isAssetInBundle(_assetId, bundleId)){
                    ids.add( _assetId );
                  }
                } else {

                    try {
                        // if the asset is a folder put the inode instead of the identifier
                        //At first we try to find the Asset Type by hitting identifier table.
                        String assetType = APILocator.getIdentifierAPI().getAssetTypeFromDB(_assetId);

                        //If we don't find the Type in table identifier we try to hit table inode.
                        if(assetType == null){
                            assetType = InodeUtils.getAssetTypeFromDB(_assetId);
                        }

                        if(assetType != null && assetType.equals(Identifier.ASSET_TYPE_FOLDER)){
                            Folder folder = null;

                            try {
                                folder = APILocator.getFolderAPI().find( _assetId, getUser(), false );
                            } catch ( DotSecurityException e ) {
                                Logger.error( getClass(), "User: " + getUser() + " does not have permission to access folder. Folder identifier: " + _assetId );
                            } catch ( DotDataException e ) {
                                Logger.info( getClass(), "FolderAPI.find(): Identifier is null" );
                            }

                            if ( folder != null && UtilMethods.isSet( folder.getInode() ) ) {
                                if (!isAssetInBundle(_assetId, bundleId)) {
                                    ids.add(_assetId);
                                }
                            }

                        } else { // if the asset is not a folder and has identifier, put it, if not, put the inode
                            Identifier iden = APILocator.getIdentifierAPI().findFromInode( _assetId );
                            if ( !ids.contains( iden.getId() ) ) {//Multiples languages have the same identifier
                              if(!UtilMethods.isSet(bundleId) || !isAssetInBundle(iden.getId(), bundleId)){
                                ids.add( iden.getId() );
                              }
                            }
                        }

                    } catch ( DotStateException e ) {
                      if(!UtilMethods.isSet(bundleId) || !isAssetInBundle(_assetId, bundleId)){
                        ids.add( _assetId );
                      }
                    }
                }
            }

        }

        return ids;
    }
   
    /**
     * Validate if the asset is already included in the bundle
     * @param assetId Asset identifier
     * @param bundleId Bundle Id
     * @return true if the asset is already included.
     */
    private boolean isAssetInBundle(String assetId, String bundleId){
      PublisherAPI publisherAPI = PublisherAPI.getInstance();
    try {
      List<PublishQueueElement> assets = publisherAPI.getQueueElementsByAsset(assetId);
      for(PublishQueueElement element :  assets){
        if(element.getBundleId().equals(bundleId)){
          return true;
        }
      }
    } catch (DotPublisherException e) {
      Logger.error(RemotePublishAjaxAction.class, e.getMessage());
    }
   
      return false;
    }

}
TOP

Related Classes of com.dotcms.publisher.ajax.RemotePublishAjaxAction

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.