public int compare(XWikiAttachment attachmentOne, XWikiAttachment attachmentTwo) {
   return attachmentOne
       .getFilename()
       .toLowerCase()
       .replace('_', '-')
       .compareTo(attachmentTwo.getFilename().toLowerCase().replace('_', '-'));
 }
  public XWikiPageClassLoader(String jarWikiPage, ClassLoader parent, XWikiContext context)
      throws XWikiException {
    super(new URL[0], parent);

    XWikiDocument doc = context.getWiki().getDocument(jarWikiPage, context);
    if (!doc.isNew()) {
      List attachList = doc.getAttachmentList();
      for (int i = 0; i < attachList.size(); i++) {
        XWikiAttachment attach = (XWikiAttachment) attachList.get(i);
        String filename = attach.getFilename();
        if (filename.endsWith(".jar")) {
          String downloadURL = doc.getExternalAttachmentURL(filename, "download", context);
          try {
            addURL(new URL(downloadURL));
            if (LOGGER.isDebugEnabled()) {
              LOGGER.debug(
                  "Adding ["
                      + downloadURL
                      + "] JAR from page ["
                      + jarWikiPage
                      + "] to Groovy classloader");
            }
          } catch (Exception e) {
            LOGGER.warn(
                "Failed to add ["
                    + downloadURL
                    + "] JAR from page ["
                    + jarWikiPage
                    + "], ignoring it.");
          }
        }
      }
    }
  }
 /**
  * Make sure the attachment is associated with a document.
  *
  * @param attachment the attachment to check.
  * @throws IllegalArgumentException if attachment.getDoc() yields null.
  */
 private static void checkAttachedToDocument(final XWikiAttachment attachment) {
   if (attachment.getDoc() == null) {
     throw new IllegalArgumentException(
         "In order to use this function, the attachment ["
             + attachment.getFilename()
             + "] must be associated with a document.");
   }
 }
Пример #4
0
  /**
   * @see "XWIKI-9399: Attachment version is incremented when a document is rolled back even if the
   *     attachment did not change"
   */
  @Test
  public void rollbackDoesNotSaveUnchangedAttachment() throws Exception {
    String version = "1.1";
    String fileName = "logo.png";
    Date date = new Date();
    XWikiAttachment currentAttachment = mock(XWikiAttachment.class);
    when(currentAttachment.getAttachmentRevision(version, context)).thenReturn(currentAttachment);
    when(currentAttachment.getDate()).thenReturn(new Timestamp(date.getTime()));
    when(currentAttachment.getVersion()).thenReturn(version);
    when(currentAttachment.getFilename()).thenReturn(fileName);

    XWikiAttachment oldAttachment = mock(XWikiAttachment.class);
    when(oldAttachment.getFilename()).thenReturn(fileName);
    when(oldAttachment.getVersion()).thenReturn(version);
    when(oldAttachment.getDate()).thenReturn(date);

    DocumentReference documentReference = new DocumentReference("wiki", "Space", "Page");
    XWikiDocument document = mock(XWikiDocument.class);
    when(document.getDocumentReference()).thenReturn(documentReference);
    when(document.getAttachmentList()).thenReturn(Arrays.asList(currentAttachment));
    when(document.getAttachment(fileName)).thenReturn(currentAttachment);

    XWikiDocument result = mock(XWikiDocument.class);
    when(result.clone()).thenReturn(result);
    when(result.getDocumentReference()).thenReturn(documentReference);
    when(result.getAttachmentList()).thenReturn(Arrays.asList(oldAttachment));
    when(result.getAttachment(fileName)).thenReturn(oldAttachment);

    String revision = "3.5";
    when(xwiki.getVersioningStore().loadXWikiDoc(document, revision, context)).thenReturn(result);

    AttachmentRecycleBinStore attachmentRecycleBinStore = mock(AttachmentRecycleBinStore.class);
    xwiki.setAttachmentRecycleBinStore(attachmentRecycleBinStore);

    DocumentReference reference = document.getDocumentReference();
    this.mocker.registerMockComponent(ContextualLocalizationManager.class);
    when(xwiki.getStore().loadXWikiDoc(any(XWikiDocument.class), same(context)))
        .thenReturn(new XWikiDocument(reference));

    xwiki.rollback(document, revision, context);

    verify(attachmentRecycleBinStore, never())
        .saveToRecycleBin(
            same(currentAttachment), any(String.class), any(Date.class), same(context), eq(true));
    verify(oldAttachment, never()).setMetaDataDirty(true);
  }
  /**
   * Set the response HTTP headers common to both partial (Range) and full responses.
   *
   * @param attachment the attachment to get content from
   * @param request the current client request
   * @param response the response to write to.
   * @param context the current request context
   */
  private static void setCommonHeaders(
      final XWikiAttachment attachment,
      final XWikiRequest request,
      final XWikiResponse response,
      final XWikiContext context) {
    // Choose the right content type
    String mimetype = attachment.getMimeType(context);
    response.setContentType(mimetype);
    try {
      response.setCharacterEncoding("");
    } catch (IllegalCharsetNameException ex) {
      response.setCharacterEncoding(XWiki.DEFAULT_ENCODING);
    }

    String ofilename = Util.encodeURI(attachment.getFilename(), context).replaceAll("\\+", "%20");

    // The inline attribute of Content-Disposition tells the browser that they should display
    // the downloaded file in the page (see http://www.ietf.org/rfc/rfc1806.txt for more
    // details). We do this so that JPG, GIF, PNG, etc are displayed without prompting a Save
    // dialog box. However, all mime types that cannot be displayed by the browser do prompt a
    // Save dialog box (exe, zip, xar, etc).
    String dispType = "inline";

    // Determine whether the user who attached the file has Programming Rights or not.
    boolean hasPR = false;
    String author = attachment.getAuthor();
    try {
      hasPR =
          context
              .getWiki()
              .getRightService()
              .hasAccessLevel("programming", author, "XWiki.XWikiPreferences", context);
    } catch (Exception e) {
      hasPR = false;
    }
    // If the mimetype is not authorized to be displayed inline, let's force its content disposition
    // to download.
    if ((!hasPR && !isAuthorized(mimetype)) || "1".equals(request.getParameter("force-download"))) {
      dispType = ATTACHMENT;
    }
    // Use RFC 2231 for encoding filenames, since the normal HTTP headers only allows ASCII
    // characters.
    // See http://tools.ietf.org/html/rfc2231 for more details.
    response.addHeader("Content-disposition", dispType + "; filename*=utf-8''" + ofilename);

    response.setDateHeader("Last-Modified", attachment.getDate().getTime());
    // Advertise that downloads can be resumed
    response.setHeader("Accept-Ranges", "bytes");
  }
Пример #6
0
  /**
   * Transforms the given image (i.e. shrinks the image and changes its quality) before it is
   * downloaded.
   *
   * @param image the image to be downloaded
   * @param width the desired image width; this value is taken into account only if it is greater
   *     than zero and less than the current image width
   * @param height the desired image height; this value is taken into account only if it is greater
   *     than zero and less than the current image height
   * @param quality the desired compression quality
   * @param context the XWiki context
   * @return the transformed image
   * @throws Exception if transforming the image fails
   */
  private XWikiAttachment downloadImage(
      XWikiAttachment image, int width, int height, float quality, XWikiContext context)
      throws Exception {
    initCache(context);

    boolean keepAspectRatio = Boolean.valueOf(context.getRequest().getParameter("keepAspectRatio"));

    XWikiAttachment thumbnail =
        (this.imageCache == null)
            ? shrinkImage(image, width, height, keepAspectRatio, quality, context)
            : downloadImageFromCache(image, width, height, keepAspectRatio, quality, context);

    // If the image has been transformed, update the file name extension to match the image format.
    String fileName = thumbnail.getFilename();
    String extension =
        StringUtils.lowerCase(StringUtils.substringAfterLast(fileName, String.valueOf('.')));
    if (thumbnail != image && !Arrays.asList("jpeg", "jpg", "png").contains(extension)) {
      // The scaled image is PNG, so correct the extension in order to output the correct MIME type.
      thumbnail.setFilename(StringUtils.substringBeforeLast(fileName, ".") + ".png");
    }
    return thumbnail;
  }
Пример #7
0
  private int installDocument(
      DocumentInfo doc, boolean isAdmin, boolean backup, XWikiContext context)
      throws XWikiException {
    if (this.preserveVersion && this.withVersions) {
      // Right now importing an archive and the history revisions it contains
      // without overriding the existing document is not supported.
      // We fallback on adding a new version to the existing history without importing the
      // archive's revisions.
      this.withVersions = false;
    }

    int result = DocumentInfo.INSTALL_OK;

    if (LOGGER.isDebugEnabled()) {
      LOGGER.debug("Package installing document " + doc.getFullName() + " " + doc.getLanguage());
    }

    if (doc.getAction() == DocumentInfo.ACTION_SKIP) {
      addToSkipped(doc.getFullName() + ":" + doc.getLanguage(), context);
      return DocumentInfo.INSTALL_OK;
    }

    int status = doc.testInstall(isAdmin, context);
    if (status == DocumentInfo.INSTALL_IMPOSSIBLE) {
      addToErrors(doc.getFullName() + ":" + doc.getLanguage(), context);
      return DocumentInfo.INSTALL_IMPOSSIBLE;
    }
    if (status == DocumentInfo.INSTALL_OK
        || status == DocumentInfo.INSTALL_ALREADY_EXIST
            && doc.getAction() == DocumentInfo.ACTION_OVERWRITE) {
      XWikiDocument previousdoc = null;
      if (status == DocumentInfo.INSTALL_ALREADY_EXIST) {
        previousdoc = context.getWiki().getDocument(doc.getFullName(), context);
        // if this document is a translation: we should only delete the translation
        if (doc.getDoc().getTranslation() != 0) {
          previousdoc = previousdoc.getTranslatedDocument(doc.getLanguage(), context);
        }
        // we should only delete the previous document
        // if we are overridding the versions and/or if this is a backup pack
        if (!this.preserveVersion || this.withVersions) {
          try {
            // This is not a real document delete, it's a upgrade. To be sure to not
            // generate DELETE notification we directly use {@link XWikiStoreInterface}
            context.getWiki().getStore().deleteXWikiDoc(previousdoc, context);
          } catch (Exception e) {
            // let's log the error but not stop
            result = DocumentInfo.INSTALL_ERROR;
            addToErrors(doc.getFullName() + ":" + doc.getLanguage(), context);
            if (LOGGER.isErrorEnabled()) {
              LOGGER.error("Failed to delete document " + previousdoc.getDocumentReference());
            }
            if (LOGGER.isDebugEnabled()) {
              LOGGER.debug("Failed to delete document " + previousdoc.getDocumentReference(), e);
            }
          }
        } else if (previousdoc.hasElement(XWikiDocument.HAS_ATTACHMENTS)) {
          // We conserve the old attachments in the new documents
          List<XWikiAttachment> newDocAttachments = doc.getDoc().getAttachmentList();
          for (XWikiAttachment att : previousdoc.getAttachmentList()) {
            if (doc.getDoc().getAttachment(att.getFilename()) == null) {
              // We add the attachment to new document
              newDocAttachments.add(att);
              // But then we add it in the "to remove list" of the document
              // So the attachment will be removed from the database when XWiki#saveDocument
              // will be called
              doc.getDoc().removeAttachment(att);
            }
          }
        }
        doc.getDoc().addXObjectsToRemoveFromVersion(previousdoc);
        doc.getDoc().setOriginalDocument(previousdoc);
      }
      try {
        if (!backup) {
          doc.getDoc().setAuthorReference(context.getUserReference());
          doc.getDoc().setContentAuthorReference(context.getUserReference());
          // if the import is not a backup pack we set the date to now
          Date date = new Date();
          doc.getDoc().setDate(date);
          doc.getDoc().setContentUpdateDate(date);
        }

        if (!this.withVersions) {
          doc.getDoc().setVersion("1.1");
        }

        // Does the document to be imported already exists in the wiki ?
        boolean isNewDocument = previousdoc == null;

        // Conserve existing history only if asked for it and if this history exists
        boolean conserveExistingHistory = this.preserveVersion && !isNewDocument;

        // Does the document from the package contains history revisions ?
        boolean packageHasHistory = this.documentContainsHistory(doc);

        // Reset to initial (1.1) version when we don't want to conserve existing history and either
        // we don't
        // want the package history or this latter one is empty
        boolean shouldResetToInitialVersion =
            !conserveExistingHistory && (!this.withVersions || !packageHasHistory);

        if (conserveExistingHistory) {
          // Insert the archive from the existing document
          doc.getDoc().setDocumentArchive(previousdoc.getDocumentArchive(context));
        } else {
          // Reset or replace history
          // if there was not history in the source package then we should reset the version number
          // to 1.1
          if (shouldResetToInitialVersion) {
            // Make sure the save will not increment the version to 2.1
            doc.getDoc().setContentDirty(false);
            doc.getDoc().setMetaDataDirty(false);
          }
        }

        String saveMessage = context.getMessageTool().get("core.importer.saveDocumentComment");
        context.getWiki().saveDocument(doc.getDoc(), saveMessage, context);
        addToInstalled(doc.getFullName() + ":" + doc.getLanguage(), context);

        if ((this.withVersions && packageHasHistory) || conserveExistingHistory) {
          // we need to force the saving the document archive.
          if (doc.getDoc().getDocumentArchive() != null) {
            context
                .getWiki()
                .getVersioningStore()
                .saveXWikiDocArchive(doc.getDoc().getDocumentArchive(context), true, context);
          }
        }

        if (shouldResetToInitialVersion) {
          // If we override and do not import version, (meaning reset document to 1.1)
          // We need manually reset possible existing revision for the document
          // This means making the history empty (it does not affect the version number)
          doc.getDoc().resetArchive(context);
        }

      } catch (XWikiException e) {
        addToErrors(doc.getFullName() + ":" + doc.getLanguage(), context);
        if (LOGGER.isErrorEnabled()) {
          LOGGER.error("Failed to save document " + doc.getFullName(), e);
        }
        result = DocumentInfo.INSTALL_ERROR;
      }
    }
    return result;
  }