Dealer Branding Download
APIEngine periodically pulls dealer-logo images from FileServer and mirrors them to local folders. Reporting reads the mirror to render dealer logos on PDF reports; the SMSMedia.Directory folder is also the SMS/MMS media root.
Version differences
| v95 and earlier | v96 and later (APIEngine 1.0) | |
|---|---|---|
| Trigger | Checked on each incoming API request (DealerBrandingDownloadHandler); a cycle runs when the interval has passed since the last one | Hosted background service (DealerBrandingDownloadHostedService) that loops until shutdown |
| Interval | SMSMedia.RetryInSeconds, no minimum | Math.Max(SMSMedia.RetryInSeconds, 60) seconds |
| Mirror folders | Reports.ImagePath (skipped when empty) and SMSMedia.Directory | SMSMedia.Directory only |
SMSMedia.Directory base | Site root (~/) | Application folder (AppContext.BaseDirectory) |
How it works
- A cycle runs each time the interval in the table above has passed.
- Each cycle calls
DealerBrandModel.List("dealer_brand=dealer_brand", false), which goes through the standard FileServer pipeline (Sybase procba_file_server_getafiltered by thedealer_brand=dealer_brandtag). - For each returned file, the service compares filename /
create_date/sizeagainstdealer_images_manifest.jsonin each mirror folder. If new, changed, or missing on disk, it downloads the bytes fromFileServer.Path + guid, writes them withFileShare.None, and verifies length matches. - After processing, the manifest is rewritten and
CleanUpFilesNotInManifestdeletes any local file not in the new manifest, except files ending inmanifest.jsonanddefault.png(case-insensitive), which are always preserved.
If SMSMedia.Directory is empty the service no-ops. If the mirror directory does not exist it is created via Ibs.Utils.PathManager.CreateDirectoryWithPermissions; if it already exists, the service grants Everyone : FullControl on it before writing.
Settings (apiengine.settings)
| Field | Purpose |
|---|---|
SMSMedia.Directory | Mirror folder name, relative to the site root (v95 and earlier) or the application folder (v96 and later). Trimmed of leading/trailing slashes. Empty = service is dormant. Default: "". |
SMSMedia.RetryInSeconds | Poll interval in seconds. v96 and later clamp values below 60 to 60. Default: 300. |
Reports.ImagePath | v95 and earlier: second mirror folder, read by Crystal reports. Empty skips it. Not a mirror target in v96 and later. |
FileServer.Path | FileServer root path. Each downloaded file is fetched from FileServer.Path + guid. |
There is no separate DealerBranding config block - the same SMSMedia settings drive both SMS media and dealer-image mirroring (intentional: same on-disk directory).
Upload side
Operators upload dealer logos via POST /api/v1/dealerbrand/reportlogo/inject/{deal_id} (DealerBrandController.ReportLogoInject -> DealerBrandModel.DealerBrandInject_150_150).
- The user must pass a
v_dealeraccess check for{deal_id}. - Any existing report logo for that dealer is deleted (header + physical folder under
FileServer.Path) before the new file is injected. - The new file is stored with tags
deal_id={deal_id}&dealer_brand=dealer_brand&dealer_brand_size=150_150, descriptionDealer Brand - 150x150, and a deterministic filename{deal_id}_dealer_brand_150_150{ext}. - Note: the
_150_150is a tag/filename convention, not server-side image-dimension enforcement. The controller does not measure or resize the upload - callers are expected to send a 150x150 PNG.
Other endpoints on the same controller
| Verb | Route | Purpose |
|---|---|---|
| GET | api/v1/dealerbrand/reportlogo/retrieve/{guid} | Full image bytes |
| GET | api/v1/dealerbrand/reportlogo/thumbnail/{guid} | PNG thumbnail |
| GET | api/v1/dealerbrand/reportlogo/list | Active files (auto-applies dealer_brand=dealer_brand filter; query string is appended) |
| GET | api/v1/dealerbrand/reportlogo/showhidden | Active + soft-deleted |
| GET / POST / DELETE | api/v1/dealerbrand/reportlogo/delete/{guid} | Soft-delete header + physically delete folder under FileServer.Path (override of base FileServer behavior - see DealerBrandModel.DealerBrandDelete, MOD 08.94.12597) |
| GET / POST | api/v1/dealerbrand/reportlogo/undelete/{guid} | Reinstate soft-deleted record |
| GET / PATCH | api/v1/dealerbrand/reportlogo/update/{guid} | Replace non-security tags |
| GET / PATCH | api/v1/dealerbrand/reportlogo/audit/guid/{value}<br>audit/user/{value} | Audit trail |
| GET | api/v1/dealerbrand/reportlogo/verify/{guid} | Verify file authenticity |
The routes are the same in v95 and v96 and later. All of them require a token.
External consumer (non-APIEngine apps)
Ibs.DealerBrandingDownload (Ibs\Utils\ibsDealerBrandingDownload.cs) is a REST client that performs the same mirror logic from outside APIEngine - it authorizes against APIEngine, calls api/v1/dealerbrand/reportlogo/list, then downloads each file via api/v1/dealerbrand/reportlogo/retrieve/{guid}. It writes the same dealer_images_manifest.json and applies the same default.png / *manifest.json cleanup exclusions. Reporting (Crystal) and other external utilities use this wrapper rather than re-implementing the protocol.
Operational notes
- Manifest file:
dealer_images_manifest.jsonin each mirror folder. default.pngand any*manifest.jsonare never pruned even if absent from the manifest.- If logos are missing on reports, check the manifest timestamp and
ibs.logforChecking for new dealer images./Dealer images found: Nlines, then per fileDownloading new or updated file:/Saved N bytes to <path>(v96 and later) orFile <name> is new or updated, downloading to <path>.(v95 and earlier). - AppPool identity needs Modify on the mirror directory (the service explicitly grants
Everyone : FullControlon existing dirs as a safety net, but the directory must be reachable from the site root in v95 and earlier, orAppContext.BaseDirectoryin v96 and later).
Propagation of Deleted Branding Images
Dealer Branding images deleted in program 1537 are removed from all propagated locations, including the report service and APIEngine media.