No description
Find a file
DJP 5fb6e1957d Add debug logging and fix test files
- Added error_log debugging to process-csv.php
- Fixed test-csv.php syntax (removed use statements in code)
- Created test-process2.php for step-by-step class loading test
- All service classes load successfully in tests

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-17 17:16:21 -05:00
css Add Global to Local CSV transformation frontend with visual progress tracking 2025-11-17 16:48:43 -05:00
js Update Global to Local to create 16 separate CSV files and fix PHP compatibility 2025-11-17 17:03:51 -05:00
.gitignore Resolve .gitignore merge conflict 2025-11-17 14:44:46 -05:00
.htaccess Simplify .htaccess - remove vendor blocking 2025-11-17 15:42:11 -05:00
AuthMiddleware.php Initial commit: L'Oréal Box Asset Submission Form 2025-11-17 14:43:36 -05:00
BoxService.php Fix grandparent logic: properly get folder two levels up 2025-11-17 15:22:06 -05:00
composer.json Fix PHP version requirements for server compatibility 2025-11-17 16:51:27 -05:00
config.php Add Global to Local CSV transformation backend 2025-11-17 16:44:48 -05:00
CSVTransformer.php Fix class namespace issues - use fully qualified class names 2025-11-17 17:09:46 -05:00
date-form.html Initial commit: L'Oréal Box Asset Submission Form 2025-11-17 14:43:36 -05:00
download-csv.php Update Global to Local to create 16 separate CSV files and fix PHP compatibility 2025-11-17 17:03:51 -05:00
EmailService.php Add Global to Local CSV transformation backend 2025-11-17 16:44:48 -05:00
Global 2 Regional AC Ingest - LOreal.blueprint (1).json Add Global to Local CSV transformation backend 2025-11-17 16:44:48 -05:00
global-to-local.php Add Global to Local CSV transformation frontend with visual progress tracking 2025-11-17 16:48:43 -05:00
header.php Add Global to Local CSV transformation frontend with visual progress tracking 2025-11-17 16:48:43 -05:00
index.php Add Global to Local CSV transformation frontend with visual progress tracking 2025-11-17 16:48:43 -05:00
OMGService.php Add Global to Local CSV transformation backend 2025-11-17 16:44:48 -05:00
process-csv.php Add debug logging and fix test files 2025-11-17 17:16:21 -05:00
Project_1601654_mediaBookings.csv Update Global to Local to create 16 separate CSV files and fix PHP compatibility 2025-11-17 17:03:51 -05:00
README.md Expand README with comprehensive workflow documentation 2025-11-17 15:51:46 -05:00
submit.php Use correct Make.com API key header: x-make-apikey 2025-11-17 15:02:18 -05:00
test-csv.php Add debug logging and fix test files 2025-11-17 17:16:21 -05:00
test-process2.php Add debug logging and fix test files 2025-11-17 17:16:21 -05:00
upload-to-box.php Update Global to Local to create 16 separate CSV files and fix PHP compatibility 2025-11-17 17:03:51 -05:00
validate-box.php Fix grandparent logic: properly get folder two levels up 2025-11-17 15:22:06 -05:00

L'Oréal Box Asset Submission Form

A PHP web application for submitting Box asset information with real-time validation, SSO authentication, and webhook integration.

Features

  • Box API Integration: Real-time validation and preview of Box folders
  • SSO Authentication: Microsoft Azure AD SSO with local development mode
  • Auto-population: Master Campaign Number automatically retrieved from Box folder hierarchy
  • Real-time Preview: Display folder contents before submission
  • Webhook Integration: Submit data to Make.com webhook with response handling
  • Responsive Design: Modern UI with Montserrat font and L'Oréal brand colors

Requirements

  • PHP 7.4 or higher
  • Composer
  • Box JWT credentials
  • Web server (Apache/Nginx) or MAMP for local development

Installation

1. Install Dependencies

composer install

2. Configuration

The application uses config.php for all configuration:

Local Development Mode (Default)

'sso' => [
    'enabled' => false,  // Local mode
    'local_user' => [
        'name' => 'Dave Porter',
        'email' => 'daveporter@oliver.agency'
    ]
]

Production Mode with SSO

'sso' => [
    'enabled' => true,  // Enable SSO
    'tenant_id' => 'your-azure-tenant-id',
    'client_id' => 'your-azure-client-id'
]

3. Box JWT Configuration

The Box JWT configuration file (43984435_77m2ujl3_config.json) must be present in the root directory. This file is already configured and should not be committed to version control (it's in .gitignore).

4. Webhook Configuration

The webhook is pre-configured in config.php:

'webhook' => [
    'url' => 'https://hook.us1.make.celonis.com/ddxrhuykysnbxqvb25uxsg0pjngqytiv',
    'api_key' => 'E4P9923eBaUTKrEr.iqvHtVHcZ6L!WH'
]

Project Structure

Loreal-master-Entry/
├── config.php                 # Application configuration
├── AuthMiddleware.php         # SSO authentication handler
├── BoxService.php             # Box API integration
├── index.php                  # Main form page
├── validate-box.php           # AJAX endpoint for Box validation
├── submit.php                 # Form submission handler
├── css/
│   └── styles.css            # Application styles
├── js/
│   └── app.js                # Frontend JavaScript
├── vendor/                    # Composer dependencies
└── 43984435_77m2ujl3_config.json  # Box JWT config (not in git)

Usage

Local Development (MAMP)

  1. Place the project in your MAMP htdocs directory
  2. Ensure config.php has 'enabled' => false for SSO
  3. Access via http://localhost:8888/Loreal-master-Entry/

Production Deployment

  1. Upload to Apache server
  2. Update config.php:
    • Set 'enabled' => true for SSO
    • Add Azure tenant and client IDs
    • Set 'debug' => false
  3. Ensure .htaccess is configured if needed
  4. Verify Box JWT config file is present

Workflow Overview

This application streamlines the process of submitting L'Oréal campaign assets stored in Box by automatically extracting metadata and sending it to downstream workflows via Make.com webhook.

Purpose

When campaign assets are uploaded to Box, this tool:

  1. Validates the folder structure
  2. Extracts campaign metadata from Box folder hierarchy
  3. Catalogs all submitted assets (files and folders)
  4. Sends structured data to Make.com for further processing
  5. Tracks submission dates and user information

Box Folder Structure Requirements

The application expects a specific Box folder hierarchy:

📁 [Campaign Number] (e.g., "123456")          ← Master Campaign Number (extracted)
   └─ 📁 CAMPAIGN_ASSETS
      └─ 📁 SUPPLIED_ASSETS                    ← User submits this folder's Box ID
         ├─ 📁 Images/
         ├─ 📁 Videos/
         └─ 📄 files...

Critical Validation: The submitted folder MUST be named "SUPPLIED_ASSETS" or the workflow will fail.

Data Extraction

The application extracts and processes the following data:

From Box API:

  • Master Campaign Number: Folder name two levels up (the campaign number folder)
  • Master Campaign ID: Box folder ID two levels up
  • Folder Structure: Complete recursive listing of all files and subfolders (up to 3 levels deep)
  • Asset Count: Total number of files and folders

From User Input:

  • Box ID: The Box folder ID for SUPPLIED_ASSETS
  • Supply Date: When assets were supplied (formatted as DD/MM/YYYY 00:00)
  • Live Date: Campaign go-live date (formatted as DD/MM/YYYY 00:00)
  • End Date: Campaign end date (formatted as DD/MM/YYYY 00:00)

From System:

  • User Email: Email of the person submitting (from SSO or local config)
  • User Name: Full name of submitter
  • Submission Timestamp: When the form was submitted

Complete Workflow Steps

Step 1: User Authentication

  • Local Mode: Automatically authenticated as daveporter@oliver.agency
  • Production Mode: User logs in with Microsoft Azure AD SSO

Step 2: Box ID Entry

  1. User navigates to the SUPPLIED_ASSETS folder in Box
  2. User copies the Box folder ID from the URL
  3. User enters the Box ID into the form
  4. User clicks "Lookup" button

Step 3: Box Validation (validate-box.php)

  1. Authenticate with Box: Generate JWT token using Box app credentials
  2. Retrieve Folder Info: GET /folders/{boxId} from Box API
  3. Validate Folder Name: Check if folder name is "SUPPLIED_ASSETS" (case-insensitive)
    • If not: Stop immediately with error message
    • If valid: Continue to next step
  4. Get Parent Folder: Retrieve the parent of SUPPLIED_ASSETS (CAMPAIGN_ASSETS)
  5. Get Grandparent Folder: Retrieve the parent of CAMPAIGN_ASSETS (Campaign Number)
  6. Extract Campaign Data:
    • Master Campaign Number = Grandparent folder name
    • Master Campaign ID = Grandparent folder ID
  7. Recursively Fetch Contents: Get all files/folders inside SUPPLIED_ASSETS (3 levels deep)
  8. Return Preview Data: Send back to frontend for display

Step 4: Preview Display

Frontend displays in right column:

  • Master Campaign Number
  • Master Campaign ID
  • Folder Name (SUPPLIED_ASSETS)
  • Total item count
  • Expandable/collapsible folder tree showing all nested contents

Step 5: Date Entry

User fills in three required dates:

  • Supply Date (when assets were provided)
  • Live Date (campaign launch)
  • End Date (campaign finish)

Step 6: Form Submission (submit.php)

  1. Validate Form Data: Ensure all fields are present
  2. Format Dates: Convert to DD/MM/YYYY 00:00 format
  3. Prepare Webhook Payload:
{
  "userEmail": "user@example.com",
  "userName": "John Doe",
  "boxId": "312657997260",
  "masterCampaignNumber": "123456",
  "masterCampaignId": "311743237672",
  "supplyDate": "24/03/2025 00:00",
  "liveDate": "31/03/2025 00:00",
  "endDate": "07/04/2025 00:00",
  "boxContents": {
    "folderName": "SUPPLIED_ASSETS",
    "totalItems": 45,
    "folders": [
      {
        "id": "123",
        "name": "Images",
        "type": "folder",
        "contents": {
          "folders": [...],
          "files": [...]
        }
      }
    ],
    "files": [
      {
        "id": "456",
        "name": "readme.txt",
        "type": "file"
      }
    ]
  },
  "submittedAt": "2025-11-17 19:58:45"
}

Step 7: Webhook Integration (Make.com)

  1. Send to Make.com: POST to webhook URL with x-make-apikey header
  2. Receive Response: Get status and any processing results
  3. Display to User:
    • Success: "Submission successful" + webhook response
    • Error: Show error message with details

Data Flow Diagram

User (Browser)
    ↓
[1] Enter Box ID → Click "Lookup"
    ↓
validate-box.php
    ↓
Box API (JWT Auth)
    ↓ (Folder Info + Contents)
validate-box.php
    ↓ (JSON Response)
Browser Preview Panel
    ↓
[2] User Fills Dates → Click "Submit"
    ↓
submit.php
    ↓
Make.com Webhook
    ↓ (Response)
submit.php
    ↓ (Success/Error)
User Sees Result

What Happens After Submission

The webhook sends the structured data to Make.com, which can then:

  1. Trigger downstream automation workflows
  2. Update campaign management systems
  3. Notify relevant team members
  4. Archive submission records
  5. Integrate with other L'Oréal systems

Error Handling

The application includes comprehensive validation at each step:

Box Validation Errors:

  • Invalid Box ID (404)
  • Folder not named "SUPPLIED_ASSETS"
  • Box authentication failure
  • Network/API errors

Form Validation Errors:

  • Missing required fields
  • Invalid date formats
  • Box ID not validated before submission

Webhook Errors:

  • Webhook unreachable
  • Authentication failure (API key)
  • Timeout (>30 seconds)
  • Non-200 response codes

All errors are logged and displayed to the user with actionable messages.

API Endpoints

validate-box.php

Method: POST Content-Type: application/json

Request:

{
  "boxId": "123456789"
}

Response (Success):

{
  "success": true,
  "data": {
    "boxId": "123456789",
    "folderName": "Asset Folder",
    "masterCampaignNumber": "Campaign Name",
    "masterCampaignId": "987654321",
    "contents": {
      "total": 15,
      "folders": [...],
      "files": [...]
    }
  }
}

submit.php

Method: POST Content-Type: application/json

Request:

{
  "boxId": "123456789",
  "supplyDate": "24/03/2025 00:00",
  "liveDate": "31/03/2025 00:00",
  "endDate": "07/04/2025 00:00",
  "boxData": {
    "masterCampaignNumber": "Campaign Name",
    "masterCampaignId": "987654321",
    "contents": {...}
  }
}

Response:

{
  "success": true,
  "message": "Submission successful",
  "webhookResponse": {...},
  "webhookStatus": 200
}

Security Features

  • httpOnly Cookies: Authentication tokens stored securely
  • JWT Validation: Box API uses signed JWT for authentication
  • Input Sanitization: All user inputs are validated and escaped
  • CSRF Protection: SameSite cookie attribute
  • XSS Prevention: HTML escaping in frontend
  • Sensitive Data: JWT config excluded from version control

Troubleshooting

Box Authentication Fails

  • Verify 43984435_77m2ujl3_config.json is present
  • Check private key passphrase is correct
  • Ensure Box app has proper permissions

SSO Not Working

  • Verify Azure tenant and client IDs
  • Check redirect URI matches your domain
  • Ensure HTTPS is enabled in production

Webhook Fails

  • Check webhook URL is accessible
  • Verify API key is correct
  • Check webhook timeout setting (default 30s)

Development

Testing Locally

Set SSO to disabled in config.php for instant local access without Azure AD setup.

Debugging

Enable debug mode in config.php:

'app' => [
    'debug' => true  // Shows detailed error messages
]

Note: Disable in production!

Author

Dave Porter (daveporter@oliver.agency)

Repository

https://bitbucket.org/zlalani/loreal-global-kickoff

License

Proprietary - L'Oréal/Oliver Agency