EntryPoints - Documentation/Help

Collapse
X
 
  • Time
  • Show
Clear All
new posts
  • ksargeant
    Junior Member
    • Mar 2025
    • 6

    EntryPoints - Documentation/Help

    Hi Guys,

    I'm looking to create a publicly accessible link to attachments that are marked for public access. I was following this plan o1-mini drew up for me, however this resulted in a error 500 when I went to access the CRM.

    Please if you could lend a hand I would be very grateful.

    This is what I followed based on an old forum discussion where the OP was trying to do the same thing.

    ---

    1. **Create a Custom Entry Point:**
    - Define a new entry point in EspoCRM that will handle public access to documents.

    2. **Handle Document Access:**
    - Implement the logic to serve the document based on the provided ID and ensure proper validation to maintain security.

    3. **Configure Allowed File Types:**
    - Ensure that the entry point allows the necessary file types you intend to share publicly.

    4. **Generate Public URLs:**
    - Create URLs that include the entry point and the document ID to grant access without requiring EspoCRM credentials.

    Below is an example of how you can set up the custom entry point.

    :::artifact{identifier="custom-public-attachment" type="text/plain" title="Custom Public Attachment Entry Point"}
    ```php
    <?php

    namespace Espo\Custom\Controllers;

    use Espo\Core\Exceptions\NotFound;
    use Espo\Core\Exceptions\Forbidden;
    use Espo\Core\EntryPoint;

    class PublicAttachment extends EntryPoint
    {
    public function action()
    {
    $id = $this->getReq()->get('id');
    if (!$id) {
    throw new NotFound('No document ID provided.');
    }

    // Load the document
    $document = $this->getEntityManager()->getEntity('Document', $id);
    if (!$document || !$document->id) {
    throw new NotFound('Document not found.');
    }

    // Optional: Add validation logic here (e.g., check if the document is marked as public)

    $fileName = $document->get('fileName');
    $filePath = $document->get('path'); // Ensure this retrieves the correct file path

    if (!file_exists($filePath)) {
    throw new NotFound('File does not exist.');
    }

    // Determine the file's MIME type
    $finfo = finfo_open(FILEINFO_MIME_TYPE);
    $mimeType = finfo_file($finfo, $filePath);
    finfo_close($finfo);

    // Set headers to initiate file download
    header('Content-Description: File Transfer');
    header('Content-Type: ' . $mimeType);
    header('Content-Disposition: attachment; filename="' . basename($fileName) . '"');
    header('Expires: 0');
    header('Cache-Control: must-revalidate');
    header('Pragma: public');
    header('Content-Length: ' . filesize($filePath));

    // Clear output buffering
    ob_clean();
    flush();

    // Read the file
    readfile($filePath);
    exit;
    }
    }
    ```
    :::

    ### Steps to Implement the Custom Entry Point:

    1. **Create the Entry Point File:**
    - Save the above PHP code in a file named `PublicAttachment.php` within the `custom/Espo/Custom/Controllers/` directory of your EspoCRM installation.

    2. **Register the Entry Point:**
    - Add the new entry point to the `custom/Espo/Services/EntryPoints.php` file:
    ```php
    <?php

    return [
    'publicAttachment' => [
    'className' => 'Espo\Custom\Controllers\PublicAttachment',
    'forUser' => false, // Allows access without authentication
    ],
    ];
    ```

    3. **Deploy the Customizations:**
    - Run the following command to ensure EspoCRM recognizes the new customizations:
    ```
    php command.php rebuild
    php command.php cache-clear
    ```

    4. **Generate Public URLs:**
    - The public URL format will be:
    ```

    ```
    Replace `DOCUMENT_ID` with the actual ID of the document you want to share.

    5. **Set Allowed File Types (Optional but Recommended):**
    - To enhance security, ensure that only specific file types are accessible via the public entry point. You can add validation within the `action` method to check the MIME type or file extension before serving the file.
  • Kharg
    Senior Member
    • Jun 2021
    • 452

    #2
    Hello,

    Would you like an entrypoint for all attachments or only for attachments in the document entity?

    Would you like to control the file availability based on a bool field like 'isPublicDownloadAvailable'?

    Comment

    • dimyy
      Active Community Member
      • Jun 2018
      • 581

      #3
      You can modify this working entrypoint:

      Code:
      <?php
      
      namespace Espo\Modules\bpm2bChatCenter\EntryPoints;
      
      use Espo\Core\Api\Request;
      use Espo\Core\Api\Response;
      use Espo\Core\Di;
      use Espo\Core\EntryPoint\EntryPoint;
      use Espo\Core\Exceptions\BadRequest;
      use Espo\Core\Exceptions\NotFound;
      
      class GetMessageAttachment implements EntryPoint,
          Di\EntityManagerAware,
          Di\AclAware
      {
          use Di\EntityManagerSetter;
          use Di\AclSetter;
      
          public static $authRequired = false;
      
          public function run(Request $request, Response $response) : void
          {
              $id = $request->getQueryParam('id');
              $type = $request->getQueryParam('type');
              $attachmentId = $request->getQueryParam('attachment');
      
              if (!$id || !$type || !$attachmentId) {
                  throw new BadRequest();
              }
      
              $entity = $this->entityManager->getEntityById($type, $id);
      
              if (!$entity) {
                  throw new NotFound();
              }
      
              $entity->set('attachmentRequests',  $entity->get('attachmentRequests') + 1 );
              $this->entityManager->saveEntity($entity, ['skipHooks' => true]);
      
              /* @var \Espo\Entities\Attachment $attachment */
              $attachment = $this->entityManager->getEntityById('Attachment', $attachmentId);
      
              if (!$attachment || $attachmentId <> $attachment->getId()) {
                  throw new NotFound();
              }
      
              $fileName = $this->entityManager->getRepository('Attachment')->getFilePath($attachment);
      
              if (!file_exists($fileName)) {
                  throw new NotFound();
              }
      
              $fileType = $attachment->get('type');
      
              if ($attachment->get('type')) {
                  header('Content-Type: ' . $fileType);
              }
      
              header('Pragma: public');
              header('Content-Length: ' . filesize($fileName));
      
              readfile($fileName);
      
              exit;
          }
      }

      Comment

      • ksargeant
        Junior Member
        • Mar 2025
        • 6

        #4
        Originally posted by Kharg
        Hello,

        Would you like an entrypoint for all attachments or only for attachments in the document entity?

        Would you like to control the file availability based on a bool field like 'isPublicDownloadAvailable'?
        Ideally yes, conditional access is preferred.

        Comment

        • ksargeant
          Junior Member
          • Mar 2025
          • 6

          #5
          Originally posted by dimyy
          You can modify this working entrypoint:

          Code:
          <?php
          
          namespace Espo\Modules\bpm2bChatCenter\EntryPoints;
          
          use Espo\Core\Api\Request;
          use Espo\Core\Api\Response;
          use Espo\Core\Di;
          use Espo\Core\EntryPoint\EntryPoint;
          use Espo\Core\Exceptions\BadRequest;
          use Espo\Core\Exceptions\NotFound;
          
          class GetMessageAttachment implements EntryPoint,
          Di\EntityManagerAware,
          Di\AclAware
          {
          use Di\EntityManagerSetter;
          use Di\AclSetter;
          
          public static $authRequired = false;
          
          public function run(Request $request, Response $response) : void
          {
          $id = $request->getQueryParam('id');
          $type = $request->getQueryParam('type');
          $attachmentId = $request->getQueryParam('attachment');
          
          if (!$id || !$type || !$attachmentId) {
          throw new BadRequest();
          }
          
          $entity = $this->entityManager->getEntityById($type, $id);
          
          if (!$entity) {
          throw new NotFound();
          }
          
          $entity->set('attachmentRequests', $entity->get('attachmentRequests') + 1 );
          $this->entityManager->saveEntity($entity, ['skipHooks' => true]);
          
          /* @var \Espo\Entities\Attachment $attachment */
          $attachment = $this->entityManager->getEntityById('Attachment', $attachmentId);
          
          if (!$attachment || $attachmentId <> $attachment->getId()) {
          throw new NotFound();
          }
          
          $fileName = $this->entityManager->getRepository('Attachment')->getFilePath($attachment);
          
          if (!file_exists($fileName)) {
          throw new NotFound();
          }
          
          $fileType = $attachment->get('type');
          
          if ($attachment->get('type')) {
          header('Content-Type: ' . $fileType);
          }
          
          header('Pragma: public');
          header('Content-Length: ' . filesize($fileName));
          
          readfile($fileName);
          
          exit;
          }
          }
          Thanks I'll try this

          Comment

          • yuri
            Member
            • Mar 2014
            • 8795

            #6
            Use NoAuth trait: https://github.com/espocrm/espocrm/b...oginAs.php#L41
            If you find EspoCRM good, we would greatly appreciate if you could give the project a star on GitHub. We believe our work truly deserves more recognition. Thanks.

            Comment

            Working...