diff --git a/.agents/manifest.json b/.agents/manifest.json new file mode 100644 index 0000000000..14a04e2777 --- /dev/null +++ b/.agents/manifest.json @@ -0,0 +1,1275 @@ +{ + "agents":[ + "claude", + "copilot", + "opencode" + ], + "coldboxCliVersion":"8.13.0", + "customSkills":[], + "excludes":[], + "guidelines":[ + { + "autoGenerated":false, + "description":"BoxLang modern JVM language syntax, class structure, data types, collections, interoperability, and best practices", + "installedVersion":"8.13.0", + "name":"boxlang", + "source":"coldbox-cli", + "syncedAt":"2026-05-19T15:11:13+02:00", + "type":"core" + }, + { + "autoGenerated":false, + "description":"ColdBox HMVC framework conventions, structure, handlers, models, views, REST APIs, testing, and integrations", + "installedVersion":"8.13.0", + "name":"coldbox", + "source":"coldbox-cli", + "syncedAt":"2026-05-19T15:11:13+02:00", + "type":"core" + } + ], + "language":"boxlang", + "lastSync":"2026-05-19T15:11:17+02:00", + "mcpServers":{ + "core":[ + "boxlang", + "coldbox", + "commandbox", + "testbox", + "wirebox", + "cachebox", + "logbox" + ], + "custom":[], + "module":[ + "cfmigrations", + "cbdebugger" + ] + }, + "skills":[ + { + "description":"Use this skill for CommandBox global configuration: config set/show/clear commands, server defaults, ForgeBox API tokens, endpoint settings, proxy configuration, module settings, env var overrides (box_config_*), setting sync across machines, task runner settings, tab completion style, preferred browser, artifacts directory, and nativeShell configuration.", + "name":"commandbox-config-settings", + "owner":"ortus-boxlang", + "path":"commandbox/commandbox-config-settings", + "repo":"skills", + "sha":"c9604319038f8af9fcd702fd20c436c6271e0fa7", + "slug":"commandbox-config-settings", + "source":"commandbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"commandbox" + }, + { + "description":"Use this skill for deploying CommandBox applications to production: Docker with ortussolutions/commandbox image, environment variables for Docker, GitHub Actions with setup-commandbox action, Heroku/Dokku buildpack, Amazon Lightsail setup, starting as OS service, using server.json for repeatable deployments, and CFConfig for engine configuration.", + "name":"commandbox-deploying", + "owner":"ortus-boxlang", + "path":"commandbox/commandbox-deploying", + "repo":"skills", + "sha":"e5609f82c8e9574f1130c92e1bf778b83c927e39", + "slug":"commandbox-deploying", + "source":"commandbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"commandbox" + }, + { + "description":"Use this skill for developing CommandBox extensions: creating custom commands (CFCs with run() method), command namespaces, parameters and tab completion, WireBox DI injection, command output with print helper, running sub-commands, creating modules (ModuleConfig.cfc), module conventions (commands/models/interceptors), interceptors, lifecycle events, custom interception points, injection DSL, user settings, and linking modules for development.", + "name":"commandbox-developing", + "owner":"ortus-boxlang", + "path":"commandbox/commandbox-developing", + "repo":"skills", + "sha":"91cff5d654e2a9e567d21387d2c40217a93b8da7", + "slug":"commandbox-developing", + "source":"commandbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"commandbox" + }, + { + "description":"Use this skill for the CommandBox embedded server: starting and stopping servers, server.json configuration, JVM args, SSL/TLS setup, URL rewrites, server rules/security, multi-site hosting, server profiles (production/development), basic authentication, bindings, custom error pages, aliases, gzip compression, web roots, HTTPS redirect, and starting as an OS service.", + "name":"commandbox-embedded-server", + "owner":"ortus-boxlang", + "path":"commandbox/commandbox-embedded-server", + "repo":"skills", + "sha":"8591e67469394428a6d66fbacfc478e306182cbc", + "slug":"commandbox-embedded-server", + "source":"commandbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"commandbox" + }, + { + "description":"Use this skill for CommandBox package management: box.json configuration, installing packages from ForgeBox/Git/HTTP/folder, semantic versioning, dependencies and devDependencies, updating packages, lock files, package scripts, private packages, publishing to ForgeBox, creating packages, and code endpoints.", + "name":"commandbox-package-management", + "owner":"ortus-boxlang", + "path":"commandbox/commandbox-package-management", + "repo":"skills", + "sha":"ce49ff6fbd1accbfd0f920724a58666c121b409e", + "slug":"commandbox-package-management", + "source":"commandbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"commandbox" + }, + { + "description":"Use this skill for installing, configuring, and upgrading CommandBox CLI: Homebrew install on Mac, apt-get on Linux, Windows install, Java requirements, custom home directory, upgrading CommandBox, light/thin binaries, non-Oracle JRE setup, and first-run configuration.", + "name":"commandbox-setup", + "owner":"ortus-boxlang", + "path":"commandbox/commandbox-setup", + "repo":"skills", + "sha":"92a2efa2dc972c2e28a338c0909d7cd06a6815b6", + "slug":"commandbox-setup", + "source":"commandbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"commandbox" + }, + { + "description":"Use this skill for CommandBox task runners: creating task CFCs, targets, passing parameters, lifecycle events (preTask/postTask/onError), interactive jobs with job DSL, progress bars, async/threading with AsyncManager, watching files, running commands from tasks, shell integration, property files, downloading files, sending email from tasks, and task target dependencies.", + "name":"commandbox-task-runners", + "owner":"ortus-boxlang", + "path":"commandbox/commandbox-task-runners", + "repo":"skills", + "sha":"383953b12c7216517fe4a6c678dddf6a03d48fc5", + "slug":"commandbox-task-runners", + "source":"commandbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"commandbox" + }, + { + "description":"Use this skill for CommandBox TestBox integration: testbox run command, running tests from CLI, configuring runner URL in box.json, multiple output formats (json/antjunit), test watcher (testbox watch), CI integration, code coverage with FusionReactor, test labels and suites, and box.json testbox configuration.", + "name":"commandbox-testing", + "owner":"ortus-boxlang", + "path":"commandbox/commandbox-testing", + "repo":"skills", + "sha":"92f15326905025f9349b863ea8c493d392dcd8bc", + "slug":"commandbox-testing", + "source":"commandbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"commandbox" + }, + { + "description":"Use this skill for CommandBox CLI usage: running commands, namespaces, tab completion, system settings, environment variables, shell variables, piping, recipes, REPL, foreach loops, jq/sql/printtable commands, ad-hoc aliases, default parameters, exit codes, and interactive shell features.", + "name":"commandbox-usage", + "owner":"ortus-boxlang", + "path":"commandbox/commandbox-usage", + "repo":"skills", + "sha":"ca5296263bb1e36ab3e742b8a4c5281c49057aa4", + "slug":"commandbox-usage", + "source":"commandbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"commandbox" + }, + { + "description":"Use this skill when designing or debugging Application.bx behavior: app discovery and nesting, multi-application isolation, lifecycle events, pseudo-constructor settings, session management, mappings/javaSettings resolution, and app-scoped schedulers/watchers via this.schedulers and this.watchers.", + "name":"boxlang-application-descriptor", + "owner":"ortus-boxlang", + "path":"boxlang-developer/application-descriptor", + "repo":"skills", + "sha":"dc8a1fcc47baccf4446132e147c23d8a9d22072b", + "slug":"application-descriptor", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when writing BoxLang asynchronous code: BoxFuture, futureNew, asyncRun, asyncAll, asyncAny, asyncAllApply, executors, schedulers, thread components, parallel pipelines, file watchers, or distributed locking with bx:lock.", + "name":"boxlang-async-programming", + "owner":"ortus-boxlang", + "path":"boxlang-developer/async-programming", + "repo":"skills", + "sha":"2b648d42801beaf69cd03b1cb3dfca21e2ed9324", + "slug":"async-programming", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when writing, reviewing, or improving BoxLang code to ensure it follows community best practices for naming, structure, scoping, error handling, performance, and maintainability.", + "name":"boxlang-best-practices", + "owner":"ortus-boxlang", + "path":"boxlang-developer/best-practices", + "repo":"skills", + "sha":"f418232d4c49539cd576c2c39847374332ec05c5", + "slug":"best-practices", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when implementing caching in BoxLang applications: cache providers, cachePut/cacheGet BIFs, output caching, cache regions, distributed caching with Redis or Couchbase, TTL policies, and distributed locking.", + "name":"boxlang-caching", + "owner":"ortus-boxlang", + "path":"boxlang-developer/caching", + "repo":"skills", + "sha":"2f4de64cca4ce55e90bf953236d7f19ed823289b", + "slug":"caching", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when helping developers migrate from CFML (Adobe ColdFusion or Lucee) to BoxLang, understanding key syntax and behavioral differences, using the bx-compat-cfml compatibility module, converting CFML file types, fixing common migration issues (scopes, annotations, query params, date handling), and writing code that works on both runtimes.", + "name":"boxlang-cfml-migration", + "owner":"ortus-boxlang", + "path":"boxlang-developer/cfml-migration", + "repo":"skills", + "sha":"886502f13d1e783db86d8805698fa79ce41eddb4", + "slug":"cfml-migration", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when writing BoxLang classes, components, interfaces, inheritance hierarchies, annotations, properties, constructors, or applying object-oriented design patterns in BoxLang.", + "name":"boxlang-classes-and-oop", + "owner":"ortus-boxlang", + "path":"boxlang-developer/classes-and-oop", + "repo":"skills", + "sha":"eb11a552168881ea2a6c8fcf7e01e01a40306544", + "slug":"classes-and-oop", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when adding documentation comments to BoxLang code: writing function/class Javadoc-style comments, documenting arguments, return types, exceptions, examples, or generating structured API reference documentation for BoxLang classes and BIFs. Comments written with these conventions are compatible with DocBox API documentation generation.", + "name":"boxlang-code-documenter", + "owner":"ortus-boxlang", + "path":"boxlang-developer/code-documenter", + "repo":"skills", + "sha":"0b199119e9a8368530017646a8b295bea6000ba7", + "slug":"code-documenter", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when reviewing BoxLang code for quality, correctness, security vulnerabilities, performance issues, style violations, or when providing structured code review feedback following BoxLang best practices and security guidelines.", + "name":"boxlang-code-reviewer", + "owner":"ortus-boxlang", + "path":"boxlang-developer/code-reviewer", + "repo":"skills", + "sha":"85f0487bfafaf795e4f162e04fb695f31d933278", + "slug":"code-reviewer", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when configuring BoxLang runtime settings via boxlang.json, setting environment variables for config overrides, configuring datasources, caches, executors, modules, logging, security, or schedulers — or when helping someone understand the BoxLang configuration system.", + "name":"boxlang-configuration", + "owner":"ortus-boxlang", + "path":"boxlang-developer/configuration", + "repo":"skills", + "sha":"3b8bcd521c1de74de59b015fb7a0380b0a623e9e", + "slug":"configuration", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when writing BoxLang database code: queryExecute, bx:query, datasource configuration, parameterized queries, transactions, stored procedures, query manipulation, or preventing SQL injection.", + "name":"boxlang-database-access", + "owner":"ortus-boxlang", + "path":"boxlang-developer/database-access", + "repo":"skills", + "sha":"cab36b456165f464e27d242ae487fca8b71d0da1", + "slug":"database-access", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when deploying BoxLang applications: CommandBox server setup, Docker containers, AWS Lambda, GitHub Actions CI/CD, BoxLang Version Manager (BVM), boxlang.json runtime config, environment variables, or Spring Boot integration.", + "name":"boxlang-deployment", + "owner":"ortus-boxlang", + "path":"boxlang-developer/deployment", + "repo":"skills", + "sha":"617b01e09e20ae1c55290cd364ca5d448fe07add", + "slug":"deployment", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when generating API documentation for BoxLang or CFML projects with DocBox, including installation, CLI usage, programmatic configuration, HTML/JSON/UML/CommandBox output strategies, HTML themes, multiple sources, excludes patterns, and creating custom strategies. DocBox reads JavaDoc-style comments from your source code — see the code-documenter skill for annotation conventions.", + "name":"boxlang-docbox", + "owner":"ortus-boxlang", + "path":"boxlang-developer/docbox", + "repo":"skills", + "sha":"d282bb8d09f7d236972569e127b4086311d260af", + "slug":"docbox", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when reading, writing, copying, moving, or deleting files and directories in BoxLang: fileRead, fileWrite, fileCopy, fileMove, directoryList, directoryCreate, fileUpload, streaming large files, or processing CSV/JSON files from disk.", + "name":"boxlang-file-handling", + "owner":"ortus-boxlang", + "path":"boxlang-developer/file-handling", + "repo":"skills", + "sha":"0c3d7769be31288338b78be9d2960f1570c35bc1", + "slug":"file-handling", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when implementing BoxLang filesystem watchers: watcherNew/watcherStart/watcherStop lifecycle BIFs, WatcherInstance APIs, event payload handling, recursive directory monitoring, debounce/throttle/atomicWrites tuning, errorThreshold auto-stop behavior, and listener patterns (closure, struct, class, class name string).", + "name":"boxlang-file-watchers", + "owner":"ortus-boxlang", + "path":"boxlang-developer/file-watchers", + "repo":"skills", + "sha":"7a115f4a903e60c97e685289cf32c3ea562cf19b", + "slug":"file-watchers", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when working with BoxLang lambdas, closures, arrow functions, higher-order functions, functional array/struct pipelines (map, filter, reduce, flatMap, groupBy, etc.), destructuring, or spread syntax.", + "name":"boxlang-functional-programming", + "owner":"ortus-boxlang", + "path":"boxlang-developer/functional-programming", + "repo":"skills", + "sha":"e22adf6acd28c94ffdc40534fc1c80287a377be9", + "slug":"functional-programming", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when working with BoxLang's interceptor/event system: creating interceptors, registering announcement points, announcing custom events with announce() or announceAsync(), building pre/post operation hooks, validation interceptors, security guards, or leveraging BoxRegisterInterceptor() BIF for standalone and module-based interception.", + "name":"boxlang-interceptors", + "owner":"ortus-boxlang", + "path":"boxlang-developer/interceptors", + "repo":"skills", + "sha":"4c65657766140185294aa2f4019381ebe8f1df46", + "slug":"interceptors", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when integrating BoxLang with Java: createObject, static method calls, type conversion, importing classes, passing closures as functional interfaces, including JARs, JSR-223 scripting, or using Java libraries from BoxLang code.", + "name":"boxlang-java-integration", + "owner":"ortus-boxlang", + "path":"boxlang-developer/java-integration", + "repo":"skills", + "sha":"e4929fde4a3636767acc3234c4ea510782518807", + "slug":"java-integration", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when writing or reviewing BoxLang code covering syntax, file types, variables, scopes, operators, control flow, exception handling, type system, and modern language features like destructuring and spread syntax.", + "name":"boxlang-language-fundamentals", + "owner":"ortus-boxlang", + "path":"boxlang-developer/language-fundamentals", + "repo":"skills", + "sha":"be26e718747ea2e449de5e4da5de181b008e2668", + "slug":"language-fundamentals", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when installing, configuring, or using BoxLang modules: box install, boxlang.json module settings, BoxLang+ premium modules (bx-pdf, bx-redis, bx-csv, bx-spreadsheet), CFML compatibility, ORM, mail, and module introspection.", + "name":"boxlang-modules-and-packages", + "owner":"ortus-boxlang", + "path":"boxlang-developer/modules-and-packages", + "repo":"skills", + "sha":"c803ef6efa1e4eccd4c23abe425b06003b9b715c", + "slug":"modules-and-packages", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when building, deploying, or debugging BoxLang applications on AWS Lambda — including Lambda.bx structure, handler conventions, environment variables, SAM CLI testing, performance optimization, connection pooling, multi-function routing, and the boxlang-starter-aws-lambda project.", + "name":"boxlang-runtime-aws-lambda", + "owner":"ortus-boxlang", + "path":"boxlang-developer/runtime-aws-lambda", + "repo":"skills", + "sha":"9a492564341cdc7eb2951af6807304ab4171a9d8", + "slug":"runtime-aws-lambda", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when setting up or developing BoxLang on a Chromebook, including enabling Linux development environment, installing Java 21, installing BoxLang, setting up VS Code with the BoxLang extension, and troubleshooting ARM/Intel Chromebook issues.", + "name":"boxlang-runtime-chromebook", + "owner":"ortus-boxlang", + "path":"boxlang-developer/runtime-chromebook", + "repo":"skills", + "sha":"55346268ea6ea8836b33bd1bc069b3ab99c9dc39", + "slug":"runtime-chromebook", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when writing BoxLang CLI scripts and classes, handling command-line arguments, using the BoxLang REPL, running action commands (compile, cftranspile, featureaudit), detecting runtime context, and leveraging CLI-specific built-in functions.", + "name":"boxlang-runtime-cli-scripting", + "owner":"ortus-boxlang", + "path":"boxlang-developer/runtime-cli-scripting", + "repo":"skills", + "sha":"f623b39f13218e79dd6dca1c7d5cb11454909d45", + "slug":"runtime-cli-scripting", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when deploying BoxLang as an enterprise Java servlet application using CommandBox, configuring server.json for BoxLang, installing BoxLang modules, enabling SSL and rewrites, using BoxLang+ or BoxLang++ subscriptions with CommandBox PRO features, and production server configuration.", + "name":"boxlang-runtime-commandbox", + "owner":"ortus-boxlang", + "path":"boxlang-developer/runtime-commandbox", + "repo":"skills", + "sha":"0f80cd178074455bde770fd6293199cec1762253", + "slug":"runtime-commandbox", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when compiling BoxLang scripts to standalone native executables using MatchBox's --target native flag, cross-compiling for multiple platforms, optimizing binary size, and using Native Fusion to expose Rust functions as BoxLang built-in functions.", + "name":"boxlang-runtime-compiled-native-binaries", + "owner":"ortus-boxlang", + "path":"boxlang-developer/runtime-compiled-native-binaries", + "repo":"skills", + "sha":"4e113ed2fb7c89b0f223e595f7bde69f47d61db1", + "slug":"runtime-compiled-native-binaries", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when building BoxLang desktop applications with Electron and the BoxLang MiniServer, including process lifecycle wiring, miniserver.json-driven development control, runtime/Package.bx packaging, .boxlang-dev.json versus .boxlang.json behavior, default /app and /public mappings, and cross-platform packaging constraints.", + "name":"boxlang-runtime-desktop", + "owner":"ortus-boxlang", + "path":"boxlang-developer/runtime-desktop", + "repo":"skills", + "sha":"bf789523b17e5e6ddae4c4cb6e16b6373f7b99b6", + "slug":"runtime-desktop", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when building BoxLang desktop applications with Electron and the BoxLang MiniServer, including process lifecycle wiring, miniserver.json-driven development control, runtime/Package.bx packaging, .boxlang-dev.json versus .boxlang.json behavior, default /app and /public mappings, and cross-platform packaging constraints.", + "name":"boxlang-runtime-desktop-electron", + "owner":"ortus-boxlang", + "path":"boxlang-developer/runtime-desktop-electron", + "repo":"skills", + "sha":"a4f0a7a2247c1c0f198c24fb3dbfdfbb9d72fc90", + "slug":"runtime-desktop-electron", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when deploying BoxLang applications to DigitalOcean App Platform using the official BoxLang starter kit, setting up auto-deployment from GitHub, and understanding the MiniServer + multi-stage Docker build architecture used in the starter.", + "name":"boxlang-runtime-digitalocean-app", + "owner":"ortus-boxlang", + "path":"boxlang-developer/runtime-digitalocean-app", + "repo":"skills", + "sha":"b498346dae91555cdcfa31cda8d592b6ecc1eae6", + "slug":"runtime-digitalocean-app", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when containerizing BoxLang applications with Docker, including choosing the right image variant, running scripts, the MiniServer web runtime, environment variables, health checks, volume mounts, Docker Compose, and production deployment patterns.", + "name":"boxlang-runtime-docker", + "owner":"ortus-boxlang", + "path":"boxlang-developer/runtime-docker", + "repo":"skills", + "sha":"ccbd8233af3941146686ccef4dd0731e11446c39", + "slug":"runtime-docker", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when deploying BoxLang to ESP32 microcontrollers using MatchBox's --target esp32 flag, flashing firmware (full-flash vs fast-deploy), using watch mode for rapid iteration, accessing hardware via BoxLang BIFs, detecting the ESP32 runtime, and understanding FreeRTOS task constraints.", + "name":"boxlang-runtime-esp32", + "owner":"ortus-boxlang", + "path":"boxlang-developer/runtime-esp32", + "repo":"skills", + "sha":"e59e983c540ee40e00dc0324749ee7b8f61e109c", + "slug":"runtime-esp32", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when setting up GitHub Actions CI/CD pipelines for BoxLang projects, including the setup-boxlang action, supported inputs/outputs, installing modules, CommandBox integration, multi-engine testing, and complete workflow templates.", + "name":"boxlang-runtime-github-actions", + "owner":"ortus-boxlang", + "path":"boxlang-developer/runtime-github-actions", + "repo":"skills", + "sha":"1267db6fe25802658d892c9206b6ac2917bc9d0f", + "slug":"runtime-github-actions", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when building, testing, or deploying BoxLang applications on Google Cloud Functions Gen 2, including handler structure, FunctionRunner entry point, URI routing, environment variables, local development with the GCF invoker, and debugging.", + "name":"boxlang-runtime-google-cloud-functions", + "owner":"ortus-boxlang", + "path":"boxlang-developer/runtime-google-cloud-functions", + "repo":"skills", + "sha":"1e20c64b9e1008b58c16e80dd398aa6ff5a5ba70", + "slug":"runtime-google-cloud-functions", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when embedding BoxLang into Java applications via the JSR-223 scripting API, evaluating BoxLang code from Java, sharing data between Java and BoxLang via Bindings, building rules engines, template processors, or configurable logic using BoxLang as a scripting engine inside a JVM application.", + "name":"boxlang-runtime-jsr-223", + "owner":"ortus-boxlang", + "path":"boxlang-developer/runtime-jsr-223", + "repo":"skills", + "sha":"9cebd9c72ec48a44356efcbe8a2324310c5bd52e", + "slug":"runtime-jsr-223", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when using MatchBox, the Rust-based native implementation of BoxLang that requires no JVM, including installation, understanding the available compilation targets (native, wasm, js, esp32), the philosophy and tradeoffs vs JVM BoxLang, and choosing the right target for CLI tools, edge deployments, browser WASM, and embedded devices.", + "name":"boxlang-runtime-matchbox", + "owner":"ortus-boxlang", + "path":"boxlang-developer/runtime-matchbox", + "repo":"skills", + "sha":"0614a93c3db40284764b562e8387304f7031c210", + "slug":"runtime-matchbox", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when running BoxLang as a lightweight web server using the BoxLang MiniServer (Undertow-based), configuring miniserver.json, using the .boxlang.json project convention, enabling health checks, warmup URLs, environment variable overrides, and tuning for development and production.", + "name":"boxlang-runtime-miniserver", + "owner":"ortus-boxlang", + "path":"boxlang-developer/runtime-miniserver", + "repo":"skills", + "sha":"235de5cbffa7b9fbadf925551ba9d0cf4557ebbe", + "slug":"runtime-miniserver", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when integrating BoxLang with Spring Boot applications, including the starter dependency, MVC view resolution, template structure, accessing Spring Model attributes, configuration via application.properties, and returning BoxLang views from Spring controllers.", + "name":"boxlang-runtime-spring-boot", + "owner":"ortus-boxlang", + "path":"boxlang-developer/runtime-spring-boot", + "repo":"skills", + "sha":"492f61355f3df5a0dcd381d1a468c7cd683a0db7", + "slug":"runtime-spring-boot", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when compiling BoxLang applications to server-side WebAssembly (WASM) using MatchBox's --target wasm flag, running WASM with Wasmtime or WasmEdge, building minimal OCI containers from WASM binaries, and deploying to edge platforms like Fastly Compute or Cloudflare Workers (WASI).", + "name":"boxlang-runtime-wasm-container", + "owner":"ortus-boxlang", + "path":"boxlang-developer/runtime-wasm-container", + "repo":"skills", + "sha":"a715de92b33e75af42ccddb7c41ffd09440856d6", + "slug":"runtime-wasm-container", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when compiling BoxLang to WebAssembly or JavaScript ES modules for use in web browsers and Node.js using MatchBox's --target js or --target wasm flags, integrating with HTML pages, bundlers (Webpack/Vite), and Node.js projects.", + "name":"boxlang-runtime-wasm-in-the-browser", + "owner":"ortus-boxlang", + "path":"boxlang-developer/runtime-wasm-in-the-browser", + "repo":"skills", + "sha":"b17046c897b77692d5a1a849e7587bade507b63e", + "slug":"runtime-wasm-in-the-browser", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when creating or managing BoxLang scheduled workloads: Scheduler DSL classes, BaseScheduler/ScheduledTask fluent APIs, schedulerStart/schedulerGet/schedulerStats BIFs, cron expressions, frequency constraints, lifecycle callbacks, or HTTP-driven tasks with the bx:schedule component.", + "name":"boxlang-scheduled-tasks", + "owner":"ortus-boxlang", + "path":"boxlang-developer/scheduled-tasks", + "repo":"skills", + "sha":"5f5ff2b34c2cfa58f5a7ebee3b07996aedbb93dc", + "slug":"scheduled-tasks", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when reviewing BoxLang code or applications for security vulnerabilities, configuring security settings, preventing injection attacks, handling file uploads safely, managing secrets, or applying secure coding patterns drawn from OWASP Top 10 and CFML/Java security history.", + "name":"boxlang-security", + "owner":"ortus-boxlang", + "path":"boxlang-developer/security", + "repo":"skills", + "sha":"58ee951f16cc95d6da080dbc3d83b34c9532fa63", + "slug":"security", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when writing BoxLang markup templates (.bxm files), mixing HTML with BoxLang output expressions, using template components like bx:output, bx:loop, bx:if, bx:include, bx:script, building views, or creating any HTML-generating template files.", + "name":"boxlang-templating", + "owner":"ortus-boxlang", + "path":"boxlang-developer/templating", + "repo":"skills", + "sha":"5512163fcf67291569648a5467eeb1f6aa58702f", + "slug":"templating", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when writing, running, or debugging tests for BoxLang applications using TestBox: BDD-style describe/it specs, xUnit-style test classes, expectations (expect/toBe matchers), assertions ($assert), life-cycle methods (beforeAll/afterAll/beforeEach/afterEach/aroundEach), MockBox mocking (createMock/prepareMock/$()/$results()), mock data generation (mockData()), async testing, exception testing, focused/skipped specs, and running tests via the BoxLang CLI runner.", + "name":"boxlang-testing", + "owner":"ortus-boxlang", + "path":"boxlang-developer/testing", + "repo":"skills", + "sha":"bb0452c066e58e66aa1392ed9c5052aa09d59488", + "slug":"testing", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when building BoxLang web applications: Application.bx lifecycle, request/response handling, sessions, forms, REST APIs, HTTP clients, routing, CSRF protection, Server-Sent Events, or configuring CommandBox/MiniServer.", + "name":"boxlang-web-development", + "owner":"ortus-boxlang", + "path":"boxlang-developer/web-development", + "repo":"skills", + "sha":"9e9a42c6934c894d2fc1a08d7fae169f9f4a3183", + "slug":"web-development", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when creating, extracting, listing, or modifying ZIP archives in BoxLang using the bx:zip component: compressing directories or files, filtering entries, reading archive contents, downloading files as a ZIP, or building backup/restore workflows.", + "name":"boxlang-zip", + "owner":"ortus-boxlang", + "path":"boxlang-developer/zip", + "repo":"skills", + "sha":"6e9203e22ae65e68d848580376b8ce51f3e50518", + "slug":"zip", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when writing, reviewing, or formatting any Ortus Solutions code (BoxLang, CFML, or Java) to ensure it follows the official Ortus coding standards: indentation, spacing, brace placement, naming, alignment, comments, and structural conventions.", + "name":"ortus-coding-standards", + "owner":"ortus-boxlang", + "path":"boxlang-developer/ortus-coding-standards", + "repo":"skills", + "sha":"8d781a7f7a9f853e57ae6b5fc8382486ed8586d6", + "slug":"ortus-coding-standards", + "source":"boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when working with CacheBox as a standalone caching framework (outside ColdBox) -- installing, creating and bootstrapping the CacheFactory, configuring the DSL, choosing object stores and eviction policies, selecting cache providers (CacheBoxProvider, CF, Lucee), implementing cache-aside/stampede-protection patterns, registering standalone listeners, named caches, disk/JDBC stores, reaping, shutdown, or monitoring cache performance.", + "name":"cachebox-standalone", + "owner":"coldbox", + "path":"cachebox", + "repo":"skills", + "sha":"f898016dea1a65a0956c14c2d857673f42932121", + "slug":"cachebox", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill whenever working with LogBox -- standalone or inside a ColdBox application. Covers installation, configuration DSL (appenders, root logger, categories), all built-in appender types with their properties, logger injection via WireBox DSL, category inheritance, structured logging with extraInfo, performance patterns (can{} methods, closure messages), custom appenders, custom layouts, async logging, environment-specific config, and production best practices.", + "name":"logbox", + "owner":"coldbox", + "path":"logbox", + "repo":"skills", + "sha":"30caad842596a6cc9ea88a0d17256c9b3527db49", + "slug":"logbox", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when working with WireBox dependency injection -- bootstrapping the injector, configuring binders, creating object mappings, using the injection DSL, setting persistence scopes, applying providers to avoid scope-widening, lazy properties, property observers, object delegation, virtual inheritance, child injectors, the object populator, or WireBox event listeners. Applies to both standalone and ColdBox-integrated usage.", + "name":"wirebox-di", + "owner":"coldbox", + "path":"wirebox", + "repo":"skills", + "sha":"ae2c087631ef43d22311e970d4ae3e06bfbff20d", + "slug":"wirebox", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when integrating AI capabilities into a ColdBox application using the BoxLang AI library (bx-ai module) -- including simple chat, streaming, pipelines, agents, RAG with vector memory, document loading, tool calling, and injecting the AI service into handlers or models.", + "name":"coldbox-ai-integration", + "owner":"coldbox", + "path":"coldbox/ai-integration", + "repo":"skills", + "sha":"03f936b4d58030c5df2be1fde0fdfac04eaf1fa7", + "slug":"ai-integration", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when choosing a ColdBox application layout (flat, boxlang, or modern), scaffolding a new ColdBox project, understanding project directory structure, deciding between app structure options, or migrating from one layout to another. Use when asked about flat layout, boxlang template, modern template, app structure, project skeleton, or web root separation.", + "name":"coldbox-app-layouts", + "owner":"coldbox", + "path":"coldbox/app-layouts", + "repo":"skills", + "sha":"43c11e23553777bfc03d2dbdf06c401bc52a6b98", + "slug":"app-layouts", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when building async pipelines, working with ColdBox Futures, running parallel computations with all()/allApply()/anyOf(), registering and managing thread-pool executors, or accessing the AsyncManager via the async() helper.", + "name":"coldbox-async-programming", + "owner":"coldbox", + "path":"coldbox/async-programming", + "repo":"skills", + "sha":"e6e6f0291c9a912bd2086eb15504442cb33f2c4e", + "slug":"async-programming", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when implementing caching inside a ColdBox application -- configuring CacheBox via ColdBox.cfc or config/CacheBox.cfc, injecting caches with WireBox (cachebox:name), using getCache() in handlers, event/view output caching with setEventCacheableEntry(), view fragment caching with renderView(cache=true), query caching, cache listeners as ColdBox interceptors, Redis/distributed provider setup, or choosing between default and template caches.", + "name":"coldbox-cache-integration", + "owner":"coldbox", + "path":"coldbox/cache-integration", + "repo":"skills", + "sha":"cc99cea5e6a7091447f33907605c39e7e98e4866", + "slug":"cache-integration", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when using the ColdBox CLI (CommandBox module) to scaffold applications, generate handlers, models, services, views, layouts, interceptors, modules, ORM artifacts, tests, or manage AI integration. Covers all `coldbox create` commands, language flags (BoxLang vs CFML), app skeleton selection, feature flags (--docker, --vite, --rest, --migrations, --ai), template token patterns, layout detection, and AI integration sub-commands.", + "name":"coldbox-cli", + "owner":"coldbox", + "path":"coldbox/coldbox-cli", + "repo":"skills", + "sha":"c7db1800891b2ccc17e059247fee3946176c3f98", + "slug":"coldbox-cli", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when configuring a ColdBox application in ColdBox.cfc, setting up environments, managing module settings, defining datasources, configuring logging with LogBox, setting up caching with CacheBox, or wiring dependencies with WireBox settings.", + "name":"coldbox-configuration", + "owner":"coldbox", + "path":"coldbox/configuration", + "repo":"skills", + "sha":"610817d9e6024945ff8ede49c3d2f47f228b2e03", + "slug":"configuration", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when extending or overriding ColdBox framework internals via the Decorator pattern -- specifically creating a ControllerDecorator to wrap the main ColdBox controller, or a RequestContextDecorator to wrap and augment the request context (event) object with custom methods or overridden behavior.", + "name":"coldbox-decorators", + "owner":"coldbox", + "path":"coldbox/decorators", + "repo":"skills", + "sha":"f64ed3543ac85b2563a149dd271afdc4071c2f77", + "slug":"decorators", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when working with dependency injection inside a ColdBox application -- the ColdBox injection DSL namespaces (coldbox:, logbox:, cachebox:, wirebox:, model:), module settings injection, injecting ColdBox services (interceptors, flash, router, scheduler), configuring the WireBox binder in ColdBox context, the enhanced ColdBox binder helpers, or wiring handlers/interceptors/models via ColdBox-aware WireBox.", + "name":"coldbox-di", + "owner":"coldbox", + "path":"coldbox/wirebox-di", + "repo":"skills", + "sha":"6c46f33299d6dbd08b1cb8159ad38b5fdaa21a89", + "slug":"wirebox-di", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when writing or improving documentation comments for ColdBox application code -- handlers, models, services, interceptors, layouts, modules, and configuration files. Covers what to document, what to skip, ColdBox-specific patterns for @event/@rc/@prc, integration with DocBox annotations, and documentation standards that result in accurate, useful API docs.", + "name":"coldbox-documenter", + "owner":"coldbox", + "path":"coldbox/coldbox-documenter", + "repo":"skills", + "sha":"eb27c2d9e571294413f62d286635726de3c06500", + "slug":"coldbox-documenter", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when working with the ColdBox event object (prc/rc), managing request collections, rendering views and data responses, handling redirects with relocate(), controlling HTTP status codes, or implementing event caching in ColdBox handlers.", + "name":"coldbox-event-model", + "owner":"coldbox", + "path":"coldbox/event-model", + "repo":"skills", + "sha":"321303146880471fd242e433c7c87d468bd25536", + "slug":"event-model", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when implementing flash RAM messaging in ColdBox, using cbMessageBox for styled notifications, building POST-REDIRECT-GET patterns, persisting messages across redirects, showing success/error/warning/info alerts, or integrating flash with form validation.", + "name":"coldbox-flash-messaging", + "owner":"coldbox", + "path":"coldbox/flash-messaging", + "repo":"skills", + "sha":"bb697722d64b1b29d2899bda1bf9faaa971dbc97", + "slug":"flash-messaging", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when creating ColdBox handlers (controllers), implementing CRUD actions, adding dependency injection to handlers, working with preHandler/postHandler advices, secured actions, REST handlers, or the EventHandler base class.", + "name":"coldbox-handler-development", + "owner":"coldbox", + "path":"coldbox/handler-development", + "repo":"skills", + "sha":"736d5fd7160a5af9211130c8431267f40c1f1afc", + "slug":"handler-development", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when creating ColdBox interceptors for cross-cutting concerns, listening to framework lifecycle events, implementing security checks, logging, CORS, rate limiting, request/response transformation, or firing and listening to custom interception points.", + "name":"coldbox-interceptor-development", + "owner":"coldbox", + "path":"coldbox/interceptor-development", + "repo":"skills", + "sha":"efaa85ee780547a6a2bcaf54683ba5029af9305b", + "slug":"interceptor-development", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when creating ColdBox layouts (master page templates), building admin layouts, creating reusable view partials, implementing nested content rendering with renderView(), switching layouts dynamically per handler, or organizing HTML structure around content views.", + "name":"coldbox-layout-development", + "owner":"coldbox", + "path":"coldbox/layout-development", + "repo":"skills", + "sha":"44cb46f5d01bae9120ccf1745c3c271b04c214c1", + "slug":"layout-development", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill for all ColdBox-specific logging concerns: configuring LogBox inside a ColdBox application (config/LogBox.cfc, inline DSL, configFile pointer), per-environment log levels, injecting loggers into handlers/interceptors/services via the WireBox logbox DSL, accessing logbox from the ColdBox proxy, and logging best practices specific to the ColdBox lifecycle.", + "name":"coldbox-logging", + "owner":"coldbox", + "path":"coldbox/logging", + "repo":"skills", + "sha":"56e1058ed8032f6e528e3aab3a6167bfa3557415", + "slug":"logging", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when creating reusable ColdBox modules, writing ModuleConfig.cfc, defining module-specific routes, models, settings, and interceptors, packaging modules for ForgeBox, or building internal application sub-systems as modules.", + "name":"coldbox-module-development", + "owner":"coldbox", + "path":"coldbox/module-development", + "repo":"skills", + "sha":"671d5bfb379103846c2d704cc543f9aefe63b285", + "slug":"module-development", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when building ColdBox Proxy objects to expose ColdBox event handlers to remote callers such as ColdFusion web services, Flex/AIR, event gateways, or CFC data binding -- enabling non-HTTP protocols to participate in the ColdBox event model.", + "name":"coldbox-proxy", + "owner":"coldbox", + "path":"coldbox/coldbox-proxy", + "repo":"skills", + "sha":"1c6f0be3461e112608c113dbfbcb93fedd8f14fa", + "slug":"coldbox-proxy", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when working with the ColdBox RequestContext object (event), managing rc and prc collections, building URLs with buildLink(), detecting HTTP methods, accessing request metadata, working with flash scope, handling AJAX requests, or reading HTTP headers and body content.", + "name":"coldbox-request-context", + "owner":"coldbox", + "path":"coldbox/request-context", + "repo":"skills", + "sha":"8310906e4edf9a07a8272a79efeee085f9520c91", + "slug":"request-context", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when building RESTful APIs in ColdBox using RestHandler, creating CRUD API endpoints, implementing API versioning, handling JWT/bearer token authentication, building structured error responses, or creating resource representations with mementos.", + "name":"coldbox-rest-api-development", + "owner":"coldbox", + "path":"coldbox/rest-api-development", + "repo":"skills", + "sha":"9fc898cefb204d73dd16b849c171c0f96cf7d406", + "slug":"rest-api-development", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when reviewing ColdBox application code for correctness, security, performance, testability, and adherence to ColdBox conventions. Covers handlers, services, models, interceptors, modules, routing, ORM/OBM usage, REST APIs, dependency injection patterns, and common anti-patterns to flag during pull request reviews.", + "name":"coldbox-reviewer", + "owner":"coldbox", + "path":"coldbox/coldbox-reviewer", + "repo":"skills", + "sha":"63140ed81a7ab1710f41b8cc53c6cfd5eed5d52d", + "slug":"coldbox-reviewer", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when configuring ColdBox routes, setting up RESTful resource routes, creating route groups, implementing URL pattern matching with constraints, defining named routes, or working with Router.cfc in a ColdBox application.", + "name":"coldbox-routing-development", + "owner":"coldbox", + "path":"coldbox/routing-development", + "repo":"skills", + "sha":"1a79fd2bda15e3e3f6045c83087c89320477229a", + "slug":"routing-development", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when creating ColdBox scheduled tasks, building Scheduler.cfc files, registering task frequencies, managing task life-cycles (before/after/onFailure/onSuccess), using server fixation for clustered apps, or configuring module schedulers.", + "name":"coldbox-scheduled-tasks", + "owner":"coldbox", + "path":"coldbox/scheduled-tasks", + "repo":"skills", + "sha":"ea3dd624105f8ccba98a45bc2383125b49a84aa8", + "slug":"scheduled-tasks", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill to understand which ColdBox testing base class to extend for a given test type, configure test bundle annotations (appMapping, configMapping, unloadColdBox, loadColdBox, coldboxAppKey), set up the tests/ harness (Application.cfc, folder structure), or choose between integration testing (BaseTestCase), isolated handler testing (BaseHandlerTest), model unit testing (BaseModelTest), and interceptor unit testing (BaseInterceptorTest).", + "name":"coldbox-testing-base-classes", + "owner":"coldbox", + "path":"coldbox/testing-base-classes", + "repo":"skills", + "sha":"01e96956d348adfa8d446e33a8c6963466ebcd1c", + "slug":"testing-base-classes", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when testing ColdBox event handlers with execute(), asserting rc/prc collections, verifying view selection and rendered output, mocking relocations, testing renderData() and getHandlerResults(), setting HTTP methods and headers, injecting mocks into handlers, or using BaseHandlerTest for isolated handler unit tests.", + "name":"coldbox-testing-handler", + "owner":"coldbox", + "path":"coldbox/testing-handler", + "repo":"skills", + "sha":"04e67320a521e02fab7c70f5ef2cfb1b91d795ec", + "slug":"testing-handler", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when simulating HTTP requests in ColdBox tests using the get(), post(), put(), patch(), delete(), or request() methods, setting request headers (Authorization, Accept, Content-Type), sending JSON request bodies, asserting response status with toHaveStatus(), checking validation errors with toHaveInvalidData(), or understanding the difference between execute() (event-based) and the HTTP method helpers (route/URL-based).", + "name":"coldbox-testing-http-methods", + "owner":"coldbox", + "path":"coldbox/testing-http-methods", + "repo":"skills", + "sha":"9a103b8c95fc0825bf924d27461e5d9446339c98", + "slug":"testing-http-methods", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when writing integration tests for ColdBox that use real dependencies (database, WireBox, ColdBox context), testing full request/response cycles with execute(), setting up and tearing down test databases, testing services with real data, or using BaseTestCase for end-to-end handler tests with actual WireBox injections.", + "name":"coldbox-testing-integration", + "owner":"coldbox", + "path":"coldbox/testing-integration", + "repo":"skills", + "sha":"4866ae271b328b4320cf14700298bf12d6aebd90", + "slug":"testing-integration", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when unit testing ColdBox interceptors in isolation using BaseInterceptorTest, accessing the pre-wired interceptor variable, leveraging mock helpers (mockController, mockRequestService, mockLogger, mockLogBox, mockFlash), configuring interceptor properties with configProperties, calling interceptor announce points directly, or scaffolding interceptor tests with CommandBox.", + "name":"coldbox-testing-interceptor", + "owner":"coldbox", + "path":"coldbox/testing-interceptor", + "repo":"skills", + "sha":"f6365993c953fb179508fb19157e309fe1892f00", + "slug":"testing-interceptor", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when unit testing ColdBox model objects (services, repositories, entities, or utility classes) in isolation using BaseModelTest, accessing the pre-wired model variable, leveraging the built-in mock helpers (mockLogger, mockLogBox, mockCacheBox, mockWireBox), calling model.init() to initialize the component, mocking injected properties with prepareMock(), or scaffolding model tests with CommandBox.", + "name":"coldbox-testing-model", + "owner":"coldbox", + "path":"coldbox/testing-model", + "repo":"skills", + "sha":"18aa810dbfb57766e02d2c85486c94181569b0a2", + "slug":"testing-model", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when rendering views and partials in ColdBox, creating reusable view components, caching view output, passing data to views, rendering views from services, using renderView() inline, or dynamically selecting views based on context.", + "name":"coldbox-view-rendering", + "owner":"coldbox", + "path":"coldbox/view-rendering", + "repo":"skills", + "sha":"9809a1282144ccdea09a808ff836eab4d8716771", + "slug":"view-rendering", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when managing database schema changes in ColdBox/BoxLang using cfmigrations and commandbox-migrations. Covers migration file structure, Schema Builder API, seeding, and CLI workflows for creating, running, and rolling back migrations safely.", + "name":"database-migrations", + "owner":"coldbox", + "path":"coldbox/database-migrations", + "repo":"skills", + "sha":"19f109117d052ff86031a61794f288b08371a41e", + "slug":"database-migrations", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when working with WireBox Aspect-Oriented Programming (AOP) -- activating the AOP engine (Mixer listener), creating method interceptor aspects, registering aspects via mapAspect(), binding aspects to classes and methods via bindAspect(), using the Matcher DSL (any, regex, mappings, instanceOf, annotatedWith, methods, returns), auto-aspect binding via classMatcher/methodMatcher annotations, the MethodInvocation API (proceed, getArgs, getTarget, getMethod), using built-in aspects (CFTransaction, HibernateTransaction, MethodLogger), and AOP in both standalone WireBox and ColdBox applications.", + "name":"wirebox-aop", + "owner":"coldbox", + "path":"coldbox/wirebox-aop", + "repo":"skills", + "sha":"666d086e70ec142510e65634078fe9bf0ac98543", + "slug":"wirebox-aop", + "source":"coldbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when using the TestBox $assert object for xUnit-style assertions: isTrue, isEqual, includes, isEmpty, key, instanceOf, throws, between, closeTo, lengthOf, match, null, typeOf, and others; registering custom assertion functions with addAssertions(); or using BoxLang dynamic assertion methods (assertIsTrue, assertBetween, etc.).", + "name":"testbox-assertions", + "owner":"coldbox", + "path":"testbox/assertions", + "repo":"skills", + "sha":"b9f69242900067525bc5481ea0be708d7ab742b3", + "slug":"assertions", + "source":"testbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when writing BDD-style tests with TestBox using describe/it blocks, feature/story/scenario/given/when/then Gherkin-style suites, lifecycle hooks (beforeAll/afterAll/beforeEach/afterEach/aroundEach), focused specs (fit/fdescribe), skipping specs (xit/xdescribe/skip()), spec data binding, asyncAll parallel specs, nested suite trees, labels, or organizing tests around behavior descriptions.", + "name":"testbox-bdd", + "owner":"coldbox", + "path":"testbox/bdd", + "repo":"skills", + "sha":"1ecc38615b9defbae445f3b97b09595fbb65c376", + "slug":"bdd", + "source":"testbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when generating realistic fake/mock data in tests using cbMockData (WireBox ID: MockData@cbMockData): age, boolean, date, datetime, email, fname, lname, name, num, sentence, ssn, string, tel, uuid, url, words, lorem, baconlorem, imageurl, ipaddress, autoincrement, oneof, rnd/rand; generating arrays of objects, nested objects, arrays of values, or using custom supplier closures.", + "name":"testbox-cbmockdata", + "owner":"coldbox", + "path":"testbox/cbmockdata", + "repo":"skills", + "sha":"3cbeb192c3ea265d8aee66d8f82b2e9e52a090e6", + "slug":"cbmockdata", + "source":"testbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when writing fluent expectations in TestBox using expect(), expectAll(), all built-in matchers (toBe, toBeTrue, toBeArray, toHaveKey, toThrow, toMatch, toBeBetween, toBeCloseTo, toInclude, etc.), the not operator (notToBe, notToBeEmpty, etc.), chaining multiple matchers on one expect(), creating custom matchers with addMatchers(), or using expectAll() over collections.", + "name":"testbox-expectations", + "owner":"coldbox", + "path":"testbox/expectations", + "repo":"skills", + "sha":"1d26f7ae9dd658b45cb4b4155ee6426634d8a315", + "slug":"expectations", + "source":"testbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when implementing TestBox run listeners (callbacks): onBundleStart, onBundleEnd, onSuiteStart, onSuiteEnd, onSpecStart, onSpecEnd; building progress indicators, custom loggers, or live dashboards that react to test lifecycle events; or passing listener callbacks to TestBox's run(), runRaw(), or the standalone runner.", + "name":"testbox-listeners", + "owner":"coldbox", + "path":"testbox/listeners", + "repo":"skills", + "sha":"18e8847c44d32aa4d9a7b3a9b24ae60ee2c47fe3", + "slug":"listeners", + "source":"testbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when creating mocks, stubs, and spies in TestBox using MockBox: createMock(), createEmptyMock(), prepareMock(), stubbing methods with $(), chaining $args()/$results()/$throws(), verifying call counts with $once()/$never()/$times()/$atLeast()/$atMost(), reading call logs with $callLog(), injecting mock properties with $property(), simulating queries with querySim(), or spying on real methods with $spy().", + "name":"testbox-mockbox", + "owner":"coldbox", + "path":"testbox/mockbox", + "repo":"skills", + "sha":"081ec8e30c50c0fcb79fd74a668abf1bd17abaac", + "slug":"mockbox", + "source":"testbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when selecting or configuring TestBox reporters: ANTJunit, Console, Doc, JSON, JUnit, Min, MinText, Simple, Text, XML, Streaming; setting reporter options (hideSkipped, editor links for Simple reporter); or creating a custom reporter by implementing the IReporter interface.", + "name":"testbox-reporters", + "owner":"coldbox", + "path":"testbox/reporters", + "repo":"skills", + "sha":"b1d4aeaf3f5f53678789e1a6abc744f0af7f0d4e", + "slug":"reporters", + "source":"testbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when running TestBox tests: CommandBox CLI (testbox run), BoxLang CLI (./testbox/run), HTML web runner, programmatic TestBox instantiation (run/runRaw/runRemote), configuring test directories or bundles, using the streaming runner (--stream flag / StreamingRunner), watcher mode, all CLI flags (--show-failed-only, --dry-run, --slow-threshold-ms, --stacktrace, --max-failures), or setting up box.json testbox configuration.", + "name":"testbox-runners", + "owner":"coldbox", + "path":"testbox/runners", + "repo":"skills", + "sha":"a867d4b47e12ddb7a089711708178a5e34fd6a56", + "slug":"runners", + "source":"testbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when writing xUnit-style tests in TestBox using test functions (testXxx()), setup/teardown lifecycle (beforeTests/afterTests/setup/teardown), $assert assertion object, or the Arrange-Act-Assert (AAA) pattern for unit testing services, models, and utilities in isolation.", + "name":"testbox-unit-xunit", + "owner":"coldbox", + "path":"testbox/unit", + "repo":"skills", + "sha":"0386bf0630ec26447427880dff12d83e9db4e233", + "slug":"unit", + "source":"testbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when setting up code coverage analysis for ColdBox/ColdFusion/BoxLang applications, configuring coverage reporting, integrating coverage with CI pipelines, using TestBox coverage options, interpreting coverage metrics, or improving test coverage of untested code paths.", + "name":"testing-coverage", + "owner":"coldbox", + "path":"testbox/testing-coverage", + "repo":"skills", + "sha":"8d04975dcdd3cf107d13cae04c40905f77460c92", + "slug":"testing-coverage", + "source":"testbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when creating test fixtures, factory patterns, or test data builders in ColdBox/TestBox, setting up shared fixture files, creating user/model factories with overrides, using cbMockData for realistic fake data generation, or managing test data setup and teardown.", + "name":"testing-fixtures", + "owner":"coldbox", + "path":"testbox/testing-fixtures", + "repo":"skills", + "sha":"c24b6d41bcf5565eaa89cb4be2c880c01273c729", + "slug":"testing-fixtures", + "source":"testbox", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"core" + }, + { + "description":"Use this skill when installing, configuring, or using the CBDebugger visual debugging panel in a ColdBox application. Covers enabling the panel in development, performance profiling, SQL query tracking, cache monitoring, request inspection, and ensuring the debugger is disabled in production.", + "name":"cbdebugger", + "owner":"coldbox", + "path":"modules/cbdebugger", + "repo":"skills", + "sha":"230a06137bb813f591d6c2eec6d972e8b9a6d655", + "slug":"cbdebugger", + "source":"cbdebugger", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"module" + }, + { + "description":"Use this skill when configuring CommandBox to run BoxLang server instances, using the BoxLang REPL, running BoxLang task runners, and managing BoxLang modules via CommandBox. Covers server.json BoxLang configuration, CLI commands, module installation, and the BoxLang-specific CommandBox workflow.", + "name":"commandbox-boxlang", + "owner":"coldbox", + "path":"modules/commandbox-boxlang", + "repo":"skills", + "sha":"d26c66c5375478e480acc69ec2b7b28e78816931", + "slug":"commandbox-boxlang", + "source":"commandbox-boxlang", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"module" + }, + { + "description":"Use this skill when running database migrations from the CommandBox CLI using commandbox-migrations, including migrate up/down/reset/refresh, creating migration files, running seeders, and checking migration status. Covers CI/CD usage, configuration, and all CLI commands for cfmigrations.", + "name":"commandbox-migrations", + "owner":"coldbox", + "path":"modules/commandbox-migrations", + "repo":"skills", + "sha":"7450f3afd0462a395a5ce0f349662bc7ff42dd69", + "slug":"commandbox-migrations", + "source":"commandbox-migrations", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"module" + }, + { + "description":"Use this skill when inspecting all registered ColdBox routes using the route-visualizer module. Covers installation as a development dependency, accessing the route-visualizer UI, understanding the route table output, and restricting access to development environments.", + "name":"route-visualizer", + "owner":"coldbox", + "path":"modules/route-visualizer", + "repo":"skills", + "sha":"71daacc7e0b03642a9caa8838c1d1f4bbab3f152", + "slug":"route-visualizer", + "source":"route-visualizer", + "syncedAt":"2026-05-19T15:11:17+02:00", + "type":"module" + } + ], + "templateType":"flat" +} diff --git a/.bxformat.json b/.bxformat.json new file mode 100644 index 0000000000..59154e7d49 --- /dev/null +++ b/.bxformat.json @@ -0,0 +1,125 @@ +{ + "indentSize" : 4, + "tabIndent" : true, + "maxLineLength" : 120, + "newLine" : "\n", + "singleQuote" : false, + "preserveStringQuotes" : false, + "alignConsecutiveAssignments" : true, + "alignConsecutiveProperties" : false, + "bracketPadding" : true, + "parensPadding" : true, + "binaryOperatorsPadding" : true, + "semicolons" : true, + "cfFormatCompatibility" : true, + "sourceType" : null, + "struct" : { + "padding" : true, + "empty_padding" : false, + "quote_keys" : false, + "separator" : ": ", + "multiline" : { + "element_count" : 5, + "comma_dangle" : false, + "leading_comma" : { + "enabled" : false, + "padding" : true + }, + "min_length" : 60 + } + }, + "property" : { + "multiline" : { + "element_count" : 5, + "comma_dangle" : false, + "leading_comma" : { + "enabled" : false, + "padding" : true + }, + "min_length" : 80 + }, + "key_value" : { + "padding" : false + } + }, + "array" : { + "padding" : true, + "empty_padding" : false, + "multiline" : { + "element_count" : 5, + "comma_dangle" : false, + "leading_comma" : { + "enabled" : false, + "padding" : true + }, + "min_length" : 60 + } + }, + "for_loop_semicolons" : { + "padding" : true + }, + "function" : { + "style" : "preserve", + "parameters" : { + "padding" : true, + "empty_padding" : false, + "comma_dangle" : false, + "multiline_count" : 5, + "multiline_length" : 50 + }, + "arrow" : { + "parens" : "always" + } + }, + "arguments" : { + "padding" : true, + "empty_padding" : false, + "comma_dangle" : false, + "multiline_count" : 3, + "multiline_length" : 60 + }, + "braces" : { + "style" : "same-line", + "require_for_single_statement" : true, + "else" : { + "style" : "same-line" + } + }, + "operators" : { + "position" : "end", + "comparison_style" : "preserve", + "ternary" : { + "style" : "flat", + "question_position" : "start" + } + }, + "chain" : { + "break_count" : 3, + "break_length" : 2147483647 + }, + "template" : { + "component_prefix" : "bx", + "indent_content" : false, + "single_attribute_per_line" : false, + "self_closing" : false + }, + "import" : { + "sort" : true, + "group" : false + }, + "comments" : { + "preserve_blank_lines" : true, + "wrap" : false + }, + "class" : { + "member_order" : "preserve", + "member_spacing" : 1, + "property_order" : "preserve", + "method_order" : "preserve", + "method_grouping" : true + }, + "sql" : { + "uppercase_keywords" : true, + "indent_clauses" : true + } +} \ No newline at end of file diff --git a/.bxlint.json b/.bxlint.json new file mode 100644 index 0000000000..d5293c8f08 --- /dev/null +++ b/.bxlint.json @@ -0,0 +1,62 @@ +{ + "include": [], + "exclude": [ + "**/boxlang_modules/**", + "**/build/**", + "**/.gradle/**", + "**/node_modules/**", + "modules/contentbox/modules/contentbox-deps/**", + "coldbox/**", + "testbox/**" + ], + "diagnostics": { + "unusedVariable": { + "enabled": true, + "severity": "hint" + }, + "unscopedVariable": { + "enabled": true, + "severity": "warning" + }, + "duplicateMethod": { + "enabled": true, + "severity": "error" + }, + "duplicateProperty": { + "enabled": true, + "severity": "error" + }, + "emptyCatchBlock": { + "enabled": true, + "severity": "warning" + }, + "invalidExtends": { + "enabled": false, + "severity": "error" + }, + "invalidImplements": { + "enabled": false, + "severity": "error" + }, + "missingReturnStatement": { + "enabled": true, + "severity": "warning" + }, + "shadowedVariable": { + "enabled": true, + "severity": "warning" + }, + "unreachableCode": { + "enabled": true, + "severity": "warning" + }, + "unusedImport": { + "enabled": true, + "severity": "warning" + }, + "unusedPrivateMethod": { + "enabled": false, + "severity": "warning" + } + } +} \ No newline at end of file diff --git a/.cfconfig.json b/.cfconfig.json index b01addd535..b8a27495da 100644 --- a/.cfconfig.json +++ b/.cfconfig.json @@ -1,6 +1,4 @@ { - "systemErr":"System", - "systemOut":"System", "componentCacheEnabled":false, "saveClassFiles":false, "robustExceptionEnabled":true, @@ -12,6 +10,7 @@ "whitespaceManagement":"white-space-pref", "postParametersLimit" : 200, "cacheDefaultObject":"contentbox", + "enableNestedTransactions" : false, "caches":{ "contentbox":{ "storage":"true", diff --git a/.cfformat.json b/.cfformat.json deleted file mode 100644 index 750c2f588e..0000000000 --- a/.cfformat.json +++ /dev/null @@ -1,63 +0,0 @@ -{ - "array.empty_padding": false, - "array.padding": true, - "array.multiline.min_length": 50, - "array.multiline.element_count": 2, - "array.multiline.leading_comma.padding": true, - "array.multiline.leading_comma": false, - "alignment.consecutive.assignments": true, - "alignment.consecutive.properties": false, - "alignment.consecutive.params": true, - "alignment.doc_comments" : true, - "brackets.padding": true, - "comment.asterisks": "align", - "binary_operators.padding": true, - "for_loop_semicolons.padding": true, - "function_call.empty_padding": false, - "function_call.padding": true, - "function_call.multiline.leading_comma.padding": true, - "function_call.casing.builtin": "cfdocs", - "function_call.casing.userdefined": "camel", - "function_call.multiline.element_count": 3, - "function_call.multiline.leading_comma": false, - "function_call.multiline.min_length": 50, - "function_declaration.padding": true, - "function_declaration.empty_padding": false, - "function_declaration.multiline.leading_comma": false, - "function_declaration.multiline.leading_comma.padding": true, - "function_declaration.multiline.element_count": 3, - "function_declaration.multiline.min_length": 50, - "function_declaration.group_to_block_spacing": "compact", - "function_anonymous.empty_padding": false, - "function_anonymous.group_to_block_spacing": "compact", - "function_anonymous.multiline.element_count": 3, - "function_anonymous.multiline.leading_comma": false, - "function_anonymous.multiline.leading_comma.padding": true, - "function_anonymous.multiline.min_length": 50, - "function_anonymous.padding": true, - "indent_size": 4, - "keywords.block_to_keyword_spacing": "spaced", - "keywords.group_to_block_spacing": "spaced", - "keywords.padding_inside_group": true, - "keywords.spacing_to_block": "spaced", - "keywords.spacing_to_group": true, - "keywords.empty_group_spacing": false, - "max_columns": 120, - "metadata.multiline.element_count": 3, - "metadata.multiline.min_length": 50, - "method_call.chain.multiline" : 3, - "newline":"\n", - "property.multiline.element_count": 3, - "property.multiline.min_length": 30, - "parentheses.padding": true, - "strings.quote": "double", - "strings.attributes.quote": "double", - "struct.separator": " : ", - "struct.padding": true, - "struct.empty_padding": false, - "struct.multiline.leading_comma": false, - "struct.multiline.leading_comma.padding": true, - "struct.multiline.element_count": 2, - "struct.multiline.min_length": 60, - "tab_indent": true -} diff --git a/.cflintrc b/.cflintrc deleted file mode 100644 index 9a4e05e296..0000000000 --- a/.cflintrc +++ /dev/null @@ -1,149 +0,0 @@ -{ - "rule": [], - "includes": [ - { - "code": "AVOID_USING_CFINCLUDE_TAG" - }, - { - "code": "AVOID_USING_CFABORT_TAG" - }, - { - "code": "AVOID_USING_CFEXECUTE_TAG" - }, - { - "code": "AVOID_USING_DEBUG_ATTR" - }, - { - "code": "AVOID_USING_ABORT" - }, - { - "code": "AVOID_USING_ISDATE" - }, - { - "code": "AVOID_USING_ISDEBUGMODE" - }, - { - "code": "AVOID_USING_CFINSERT_TAG" - }, - { - "code": "AVOID_USING_CFUPDATE_TAG" - }, - { - "code": "ARG_VAR_CONFLICT" - }, - { - "code": "ARG_HINT_MISSING" - }, - { - "code": "ARG_HINT_MISSING_SCRIPT" - }, - { - "code": "ARGUMENT_INVALID_NAME" - }, - { - "code": "ARGUMENT_ALLCAPS_NAME" - }, - { - "code": "ARGUMENT_IS_TEMPORARY" - }, - { - "code": "CFQUERYPARAM_REQ" - }, - { - "code": "COMPARE_INSTEAD_OF_ASSIGN" - }, - { - "code": "COMPONENT_HINT_MISSING" - }, - { - "code": "COMPONENT_INVALID_NAME" - }, - { - "code": "COMPONENT_ALLCAPS_NAME" - }, - { - "code": "COMPONENT_TOO_SHORT" - }, - { - "code": "COMPONENT_TOO_LONG" - }, - { - "code": "COMPONENT_IS_TEMPORARY" - }, - { - "code": "COMPONENT_HAS_PREFIX_OR_POSTFIX" - }, - { - "code": "COMPLEX_BOOLEAN_CHECK" - }, - { - "code": "EXCESSIVE_FUNCTION_LENGTH" - }, - { - "code": "EXCESSIVE_ARGUMENTS" - }, - { - "code": "EXPLICIT_BOOLEAN_CHECK" - }, - { - "code": "FUNCTION_HINT_MISSING" - }, - { - "code": "FILE_SHOULD_START_WITH_LOWERCASE" - }, - { - "code": "LOCAL_LITERAL_VALUE_USED_TOO_OFTEN" - }, - { - "code": "GLOBAL_LITERAL_VALUE_USED_TOO_OFTEN" - }, - { - "code": "MISSING_VAR" - }, - { - "code": "METHOD_INVALID_NAME" - }, - { - "code": "METHOD_ALLCAPS_NAME" - }, - { - "code": "NESTED_CFOUTPUT" - }, - { - "code": "NEVER_USE_QUERY_IN_CFM" - }, - { - "code": "OUTPUT_ATTR" - }, - { - "code": "QUERYPARAM_REQ" - }, - { - "code": "UNUSED_LOCAL_VARIABLE" - }, - { - "code": "UNUSED_METHOD_ARGUMENT" - }, - { - "code": "SQL_SELECT_STAR" - }, - { - "code": "SCOPE_ALLCAPS_NAME" - }, - { - "code": "VAR_ALLCAPS_NAME" - }, - { - "code": "VAR_INVALID_NAME" - } - ], - "inheritParent": false, - "parameters": { - "TooManyFunctionsChecker.maximum": 20 - }, - "excludes": [ - { - "code": "ARG_VAR_MIXED" - } - ] -} \ No newline at end of file diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..089cc640d7 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,13 @@ +version: 2 +updates: + # GitHub Actions - updates uses: statements in workflows + - package-ecosystem: "github-actions" + directory: "/" # Where your .github/workflows/ folder is + schedule: + interval: "quarterly" + + # NPM + - package-ecosystem: "npm" + directory: "/system/exceptions" # adjust if needed + schedule: + interval: "monthly" diff --git a/.github/workflows/cron.yml b/.github/workflows/cron.yml new file mode 100644 index 0000000000..fcf8c73667 --- /dev/null +++ b/.github/workflows/cron.yml @@ -0,0 +1,10 @@ +name: Daily Tests + +on: + schedule: + - cron: '0 0 * * 0' # Runs at 00:00 UTC every Sunday + +jobs: + tests: + uses: ./.github/workflows/tests.yml + secrets: inherit diff --git a/.github/workflows/lts.yml b/.github/workflows/lts.yml index 76399b4136..1e8875ee09 100644 --- a/.github/workflows/lts.yml +++ b/.github/workflows/lts.yml @@ -16,19 +16,24 @@ jobs: ########################################################################################## # Format Source Code ########################################################################################## - format: - name: Code Auto-Formatting - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 + # format: + # name: Code Auto-Formatting + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v6 - - name: Auto-format - uses: Ortus-Solutions/commandbox-action@v1.0.3 - with: - cmd: run-script format + # # We use snapshot here due to the fixes in BoxLang for the formatter + # # Once v1.14.0 releases, we can switch to that version + # - name: Setup BoxLang + # uses: ortus-boxlang/setup-boxlang@main + # with: + # version: snapshot - - name: Commit Format Changes - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: Apply cfformat changes - push_options: --force + # - name: Run Formatter + # run: boxlang format --source config,handlers,modules/contentbox,tests/specs + + # - name: Commit Format Changes + # uses: stefanzweifel/git-auto-commit-action@v7 + # with: + # commit_message: Apply cfformat changes + # push_options: --force diff --git a/.github/workflows/pr.yml b/.github/workflows/pr.yml index d84eac3884..20c06406e2 100644 --- a/.github/workflows/pr.yml +++ b/.github/workflows/pr.yml @@ -17,18 +17,19 @@ jobs: uses: ./.github/workflows/tests.yml secrets: inherit - format_check: - name: Checks Source Code Formatting - runs-on: ubuntu-latest - steps: - - name: Checkout Repository - uses: actions/checkout@v4 + # format_check: + # name: Checks Source Code Formatting + # runs-on: ubuntu-latest + # steps: + # - name: Checkout Repository + # uses: actions/checkout@v6 - - name: Setup CommandBox CLI - uses: Ortus-Solutions/setup-commandbox@v2.0.1 - with: - install: commandbox-cfformat - warmup: true + # # We use snapshot here due to the fixes in BoxLang for the formatter + # # Once v1.14.0 releases, we can switch to that version + # - name: Setup BoxLang + # uses: ortus-boxlang/setup-boxlang@main + # with: + # version: snapshot - - name: Run formatting rules - run: box run-script format + # - name: Run Formatter + # run: boxlang format --check --source config,handlers,modules/contentbox,tests/specs diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index e9e6b2174b..fddaed8b33 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -40,29 +40,30 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout Repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: "temurin" java-version: "21" - name: Setup CommandBox - uses: Ortus-Solutions/setup-commandbox@v2.0.1 + uses: ortus-boxlang/setup-boxlang@main with: + with-commandbox: true forgeboxAPIKey: ${{ secrets.FORGEBOX_API_TOKEN }} - - name: Install CFML Dependencies + - name: Install Dependencies run: | box install --production box install commandbox-docbox cd modules/contentbox && box install --production - - name: Install Node 18 - uses: actions/setup-node@v4 + - name: Install Node 25 + uses: actions/setup-node@v6 with: - node-version: 18 + node-version: 25 - name: Compile Release Assets run: | @@ -101,7 +102,7 @@ jobs: printf "DB_CONNECTIONSTRING=jdbc:mysql://127.0.0.1:3306/contentbox?useSSL=false&useUnicode=true&characterEncoding=UTF-8&serverTimezone=UTC&useLegacyDatetimeCode=true\n" >> .env - name: Download Test Artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 if: env.SNAPSHOT == 'true' with: path: tests/results @@ -109,21 +110,21 @@ jobs: - name: Start Docs Server if: env.SNAPSHOT == 'false' run: | - box server start serverConfigFile="server-lucee@5.json" openBrowser=false saveSettings=false + box server start serverConfigFile="server-boxlang-cfml@1.json" openBrowser=false saveSettings=false - name: Build API Docs run: | # Normalize swagger doc results if they exist - if test -f tests/results/contentbox-test-results-lucee@5-coldbox^7-experimental-false/contentbox-swagger.json; then - cp -v tests/results/contentbox-test-results-lucee@5-coldbox^7-experimental-false/contentbox-swagger.json tests/results/ + if test -f tests/results/contentbox-test-results-boxlang-cfml@1-coldbox^8-experimental-true/contentbox-swagger.json; then + cp -v tests/results/contentbox-test-results-boxlang-cfml@1-coldbox^8-experimental-true/contentbox-swagger.json tests/results/ else - echo "File tests/results/contentbox-test-results-lucee@5-coldbox^7-experimental-false/contentbox-swagger.json does not exist" + echo "File tests/results/contentbox-test-results-boxlang-cfml@1-coldbox^8-experimental-true/contentbox-swagger.json does not exist" fi # Run Docs Build - box run-script build:allDocs + box run-script build:apiDocs - name: Update changelog [unreleased] with latest version - uses: thomaseizinger/keep-a-changelog-new-release@1.3.0 + uses: thomaseizinger/keep-a-changelog-new-release@3.1.0 if: env.SNAPSHOT == 'false' with: changelogPath: ./changelog.md @@ -139,7 +140,7 @@ jobs: working-directory: build/build-contentbox - name: Commit Changelog [unreleased] with latest version - uses: EndBug/add-and-commit@v9.1.4 + uses: EndBug/add-and-commit@v10 if: env.SNAPSHOT == 'false' with: author_name: Github Actions @@ -157,7 +158,7 @@ jobs: - name: Upload Build Artifacts if: success() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: contentbox-variants path: | @@ -195,7 +196,7 @@ jobs: cd $ROOT_DIR/build/build-contentbox/installer-module && box forgebox publish - name: Create Github Release - uses: taiki-e/create-gh-release-action@v1.8.0 + uses: taiki-e/create-gh-release-action@v1.9.3 continue-on-error: true if: env.SNAPSHOT == 'false' with: @@ -226,13 +227,13 @@ jobs: needs: [ build ] steps: - name: Checkout Development Repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 if: env.LTS == 'false' with: ref: development - name: Checkout LTS Repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 if: env.LTS == 'true' - name: Setup CommandBox @@ -241,7 +242,7 @@ jobs: forgeboxAPIKey: ${{ secrets.FORGEBOX_TOKEN }} - name: Download build artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: name: contentbox-variants path: .tmp @@ -261,7 +262,7 @@ jobs: git pull - name: Commit Version Bump - uses: EndBug/add-and-commit@v9.1.4 + uses: EndBug/add-and-commit@v10 with: author_name: Github Actions author_email: info@ortussolutions.com diff --git a/.github/workflows/snapshot.yml b/.github/workflows/snapshot.yml index 1e8546b0b7..713a0aad5a 100644 --- a/.github/workflows/snapshot.yml +++ b/.github/workflows/snapshot.yml @@ -22,33 +22,35 @@ jobs: ########################################################################################## # Format Source Code ########################################################################################## - format: - name: Code Auto-Formatting - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v4 - - - name: Setup CommandBox CLI - uses: Ortus-Solutions/setup-commandbox@v2.0.1 - with: - install: commandbox-cfformat - warmup: true - - - name: Run formatting rules - run: box run-script format - - - name: Commit Format Changes - uses: stefanzweifel/git-auto-commit-action@v5 - with: - commit_message: Apply cfformat changes - push_options: --force + # Disabled until we resolve a few things + # format: + # name: Code Auto-Formatting + # runs-on: ubuntu-latest + # steps: + # - uses: actions/checkout@v6 + + # # We use snapshot here due to the fixes in BoxLang for the formatter + # # Once v1.14.0 releases, we can switch to that version + # - name: Setup BoxLang + # uses: ortus-boxlang/setup-boxlang@main + # with: + # version: snapshot + + # - name: Run Formatter + # run: boxlang format --source config,handlers,modules/contentbox,tests/specs + + # - name: Commit Format Changes + # uses: stefanzweifel/git-auto-commit-action@v7 + # with: + # commit_message: Apply cfformat changes + # push_options: --force ############################################# # Build Snapshot Release ############################################# build: uses: ./.github/workflows/release.yml - needs: [ tests, format ] + needs: [ tests ] secrets: inherit with: snapshot: true diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 3c2f8d1acb..d2ca2a523f 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -18,47 +18,34 @@ jobs: strategy: fail-fast: false matrix: - cfengine: [ "lucee@5", "adobe@2021", "adobe@2023" ] - coldboxVersion: [ "^7" ] + cfengine: [ "adobe@2023", "adobe@2025" ] + coldboxVersion: [ "^8" ] jdkVersion: [ "21" ] experimental: [ false ] include: - # Lucee 6 has a regression - - cfengine: "boxlang@1" - coldboxVersion: "^7" + # BoxLang CFML + - cfengine: "boxlang-cfml@1" + coldboxVersion: "^8" jdkVersion: "21" experimental: true - - cfengine: "boxlang@1" - coldboxVersion: "be" - jdkVersion: "21" - experimental: true - # Lucee 6 has a regression - - cfengine: "lucee@6" - coldboxVersion: "^7" + - cfengine: "boxlang-cfml@be" + coldboxVersion: "^8" jdkVersion: "21" experimental: true - # - cfengine: "adobe@2025" - # coldboxVersion: "^7" - # jdkVersion: "21" - # experimental: true # ColdBox BE on all allowed distros # This makes sure we don't have any issues with the BE of ColdBox - - cfengine: "lucee@5" + - cfengine: "boxlang-cfml@1" coldboxVersion: "be" jdkVersion: "21" experimental: true - - cfengine: "lucee@6" - coldboxVersion: "be" - jdkVersion: "21" - experimental: true - - cfengine: "adobe@2023" + - cfengine: "adobe@2025" coldboxVersion: "be" jdkVersion: "21" experimental: true steps: - name: Checkout Repository - uses: actions/checkout@v4 + uses: actions/checkout@v6 - name: Setup Database and Fixtures run: | @@ -67,7 +54,7 @@ jobs: mysql -u${{ env.DB_USER }} -p${{ env.DB_PASSWORD }} < tests/resources/sql/mysql/contentbox.sql - name: Setup Java - uses: actions/setup-java@v4 + uses: actions/setup-java@v5 with: distribution: "temurin" java-version: ${{ matrix.jdkVersion }} @@ -93,10 +80,8 @@ jobs: if: contains( matrix.cfengine, 'adobe' ) run: | # Log4j Hibernate Debug - mkdir -p .engines/acf2021/WEB-INF/cfusion/lib/ mkdir -p .engines/acf2023/WEB-INF/cfusion/lib/ mkdir -p .engines/acf2025/WEB-INF/cfusion/lib/ - cp build/resources/log4j.properties .engines/acf2021/WEB-INF/cfusion/lib/ cp build/resources/log4j.properties .engines/acf2023/WEB-INF/cfusion/lib/ cp build/resources/log4j.properties .engines/acf2025/WEB-INF/cfusion/lib/ @@ -130,7 +115,7 @@ jobs: - name: Upload Test Results Artifacts if: always() - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: contentbox-test-results-${{ matrix.cfengine }}-coldbox${{ matrix.coldboxVersion }}-experimental-${{ matrix.experimental }} path: | @@ -151,9 +136,6 @@ jobs: - name: Failure Debugging Info if: ${{ failure() }} run: | - if [[ "{{ matrix.cfengine }}" == "adobe@2021" ]] ; then - cat .engines/acf2021/WEB-INF/cfusion/logs/hibernatesql.log - fi if [[ "{{ matrix.cfengine }}" == "adobe@2023" ]] ; then cat .engines/acf2023/WEB-INF/cfusion/logs/hibernatesql.log fi @@ -165,7 +147,7 @@ jobs: - name: Upload Debugging Info To Artifacts if: ${{ failure() && !startsWith( 'pull_request', github.event_name ) }} - uses: actions/upload-artifact@v4 + uses: actions/upload-artifact@v7 with: name: Failure Debugging Info - ${{ matrix.cfengine }} jdk:${{ matrix.jdkVersion }} coldbox:${{ matrix.coldboxVersion }} path: | @@ -183,7 +165,7 @@ jobs: steps: # Download the test results - name: Download Artifacts - uses: actions/download-artifact@v4 + uses: actions/download-artifact@v8 with: path: artifacts @@ -191,3 +173,4 @@ jobs: uses: EnricoMi/publish-unit-test-result-action@v2 with: files: artifacts/**/*.xml + compare_to_earlier_commit: false diff --git a/.gitignore b/.gitignore index 0f67f25738..98f687a229 100755 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,7 @@ WEB-INF/** /*.log # Build Dependencies -coldbox/* +lib/** artifacts/** build/build.number build/apidocs/docbox @@ -24,6 +24,7 @@ config/logs/** # Engines + Docker Libraries .engines/** +.boxlang/** bin/.db/** tests/resources/dbs/.db/** @@ -52,8 +53,6 @@ modules/contentbox/themes/default/includes/js modules/contentbox/themes/default/includes/bootswatch modules/contentbox/themes/default/includes/rev-manifest.json modules/contentbox/themes/default/node_modules -modules/route-visualizer/** -modules/cbdebugger # ContentBox Dependency Modules modules/contentbox/modules/contentbox-deps/modules/* @@ -70,3 +69,7 @@ testbox/* /tests/**/logs/** /tests/test-results/* tests/resources/patches/tmp/ + +# AI Skills +.agents/skills/** +.agents/guidelines/** \ No newline at end of file diff --git a/.mcp.json b/.mcp.json new file mode 100644 index 0000000000..152917997c --- /dev/null +++ b/.mcp.json @@ -0,0 +1,40 @@ +{ + "mcpServers":{ + "boxlang":{ + "type":"http", + "url":"https://ai.ortusbooks.com/~gitbook/mcp" + }, + "cachebox":{ + "type":"http", + "url":"https://cachebox.ortusbooks.com/~gitbook/mcp" + }, + "cbdebugger":{ + "type":"http", + "url":"https://cbdebugger.ortusbooks.com/~gitbook/mcp" + }, + "cfmigrations":{ + "type":"http", + "url":"https://cfmigrations.ortusbooks.com/~gitbook/mcp" + }, + "coldbox":{ + "type":"http", + "url":"https://coldbox.ortusbooks.com/~gitbook/mcp" + }, + "commandbox":{ + "type":"http", + "url":"https://commandbox.ortusbooks.com/~gitbook/mcp" + }, + "logbox":{ + "type":"http", + "url":"https://logbox.ortusbooks.com/~gitbook/mcp" + }, + "testbox":{ + "type":"http", + "url":"https://testbox.ortusbooks.com/~gitbook/mcp" + }, + "wirebox":{ + "type":"http", + "url":"https://wirebox.ortusbooks.com/~gitbook/mcp" + } + } +} diff --git a/.vscode/mcp.json b/.vscode/mcp.json new file mode 100644 index 0000000000..db5a1138e7 --- /dev/null +++ b/.vscode/mcp.json @@ -0,0 +1,41 @@ +{ + "inputs":[], + "servers":{ + "boxlang":{ + "type":"http", + "url":"https://ai.ortusbooks.com/~gitbook/mcp" + }, + "cachebox":{ + "type":"http", + "url":"https://cachebox.ortusbooks.com/~gitbook/mcp" + }, + "cbdebugger":{ + "type":"http", + "url":"https://cbdebugger.ortusbooks.com/~gitbook/mcp" + }, + "cfmigrations":{ + "type":"http", + "url":"https://cfmigrations.ortusbooks.com/~gitbook/mcp" + }, + "coldbox":{ + "type":"http", + "url":"https://coldbox.ortusbooks.com/~gitbook/mcp" + }, + "commandbox":{ + "type":"http", + "url":"https://commandbox.ortusbooks.com/~gitbook/mcp" + }, + "logbox":{ + "type":"http", + "url":"https://logbox.ortusbooks.com/~gitbook/mcp" + }, + "testbox":{ + "type":"http", + "url":"https://testbox.ortusbooks.com/~gitbook/mcp" + }, + "wirebox":{ + "type":"http", + "url":"https://wirebox.ortusbooks.com/~gitbook/mcp" + } + } +} diff --git a/.vscode/settings.json b/.vscode/settings.json index bf804b924f..c51eb04650 100755 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,24 +1,8 @@ { - "cfml.mappings": [ - { - "logicalPath": "/contentbox", - "directoryPath": "./modules/contentbox", - "isPhysicalDirectoryPath" :false - }, - { - "logicalPath": "/coldbox", - "directoryPath": "./coldbox", - "isPhysicalDirectoryPath" :false - }, - { - "logicalPath": "/cborm", - "directoryPath": "./modules/cborm", - "isPhysicalDirectoryPath" :false - }, - { - "logicalPath": "/testbox", - "directoryPath": "./testbox", - "isPhysicalDirectoryPath" :false - } - ] + "boxlang.mappings": { + "/coldbox" : "./lib/coldbox", + "/testbox" : "./lib/testbox", + "/cborm" : "./modules/contentbox/modules/contentbox-deps/modules/cborm", + "/contentbox" : "./modules/contentbox" + } } diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..06834c8f20 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,384 @@ + + + + +# ContentBox Tester Site - AI Agent Instructions + +This is a ColdBox HMVC application using the **flat template structure** where all application code lives in the webroot. Compatible with Adobe ColdFusion 2018+, Lucee 5.x+, and BoxLang 1.0+. + +## Project Overview + +**Language Mode:** BoxLang +**ColdBox Version:** ^8 +**Template Type:** Flat (traditional webroot structure) + +## Application Structure + +``` +/ - Application root (webroot) +├── Application.cfc - Bootstrap that directly loads ColdBox +├── index.cfm - Front controller +├── config/ - Framework and app configuration +├── handlers/ - Event handlers (controllers) +├── models/ - Service objects, business logic +├── views/ - HTML templates +├── layouts/ - Page layouts wrapping views +├── includes/ - Public assets (CSS, JS, images) +├── modules_app/ - Application modules (HMVC) +├── tests/ - Test suites +└── lib/ - Framework dependencies +``` + +**Key Characteristics:** +- Everything in webroot (simpler for traditional hosting) +- No `/app` vs `/public` separation +- All code is web-accessible by default +- `COLDBOX_APP_MAPPING = ""` (empty, app at root) + +## Framework Knowledge + +Core ColdBox and language guidelines are installed in `.ai/guidelines/core/`. Supported tools +(e.g., VS Code Copilot) load them automatically via file attachments. For other agents, load them +explicitly when you need framework fundamentals: + +- `read_file` on `.ai/guidelines/core/coldbox.md` — ColdBox conventions, handlers, routing, DI reference +- `read_file` on `.ai/guidelines/core/boxlang.md` — BoxLang syntax and patterns + +## Installed Modules + +The following ColdBox modules are installed in this project. Use these when generating code, checking available services, and suggesting relevant skills or guidelines: + +No additional modules installed yet. + +## Handlers Snapshot + +Current event handlers and their public actions (auto-updated on `coldbox ai refresh`): + +- **Main**: index, onAppInit, onException, onMissingTemplate + +## Interceptors Snapshot + +Registered interceptors and their interception points (auto-updated on `coldbox ai refresh`): + +No interceptors found. + +## Layouts + +Available layouts (auto-updated on `coldbox ai refresh`): + +- **Main.cfm** + +## Custom Modules + +Application-level modules located in `/modules_app` (auto-updated on `coldbox ai refresh`): + +- **contentbox-custom** (`modules_app`) + +## AI Integration & Resources + +This project includes AI-powered development assistance with on-demand guidelines, skills, and MCP documentation servers. + +## Project-Specific Conventions + +### Code Style + +- **Semicolons:** Optional in CFML/BoxLang. Only use when demarcating properties or in inline component syntax +- **Handler naming:** Plural nouns (Users.cfc, Orders.cfc) +- **Service naming:** Descriptive with "Service" suffix (UserService.cfc) +- **Dependency injection:** Use `property name="service" inject` over manual getInstance() + +### Testing + +- Tests located in `/tests/specs/` +- Integration tests extend `BaseTestCase` with `appMapping="/app"` +- **Critical:** Always call `setup()` in `beforeEach()` for test isolation +- Run tests: `box testbox run` + +### Configuration + +- Environment variables defined in `.env` (copy from `.env.example`) +- Access via `getSystemSetting("VAR_NAME", "default")` +- Framework config in `config/ColdBox.cfc` +- Routes in `config/Router.cfc` + +### Application Helpers + +- `includes/helpers/ApplicationHelper.cfm` - Available in all handlers/views +- Add common utility functions here + +### Development Workflow + +```bash +# Install dependencies +box install + +# Start server +box server start + +# Format code +box run-script format + +# Run tests +box testbox run + +# Reinit framework (dev) +/?fwreinit=true +``` + +## AI Integration + +This project includes AI-powered development assistance with guidelines, skills, and MCP documentation servers. + +### Directory Structure + +``` +/.agents/ + /manifest.json - AI configuration (language, agents, guidelines, skills, MCP servers) + /guidelines/ - Framework documentation and best practices + /core/ - Core ColdBox/BoxLang guidelines + /modules/ - Module-specific guidelines + /custom/ - Your custom guidelines + /overrides/ - Override core guidelines + /skills/ - Framework/core implementation cookbooks (auto-managed, can be .gitignored) + /{name}/ - One folder per skill (flat, no subdirectories) + SKILL.md - Skill content (fetched from registry) + /skills-custom/ - Project-specific skills (commit these to source control) + /{name}/ - One folder per custom skill + SKILL.md - Custom skill content (project-authored or overrides) + /mcp-servers/ - MCP server configurations +``` + +### Manifest + +The `.agents/manifest.json` file contains the complete AI integration configuration: + +- **language**: Project language mode (boxlang, cfml, hybrid) +- **templateType**: Application template (modern, flat) +- **guidelines**: Array of installed guideline names +- **skills**: Array of core/framework skill names (auto-managed) +- **customSkills**: Array of project-specific skill names (in `skills-custom/`) +- **agents**: Array of configured AI agents +- **mcpServers**: Configured MCP documentation servers (core, module, custom) +- **activeAgent**: Currently active AI agent (if set) +- **lastSync**: Last synchronization timestamp + +**Reading the manifest** helps you understand available resources and project configuration. + +### Using Guidelines & Skills + +Guidelines and skills are stored locally in `.agents/` and loaded via `read_file` when needed: + +**Core Guidelines** (`.agents/guidelines/core/`) — framework fundamentals: +- `read_file` on `.agents/guidelines/core/coldbox.md` — ColdBox conventions, handler/routing/DI reference +- `read_file` on `.agents/guidelines/core/boxlang.md` — BoxLang syntax, classes, lambdas (or `cfml.md` for CFML) + +**Module/Custom Guidelines** — load by name on request from `.agents/guidelines/modules/` or `.agents/guidelines/custom/`. + +**Skills** (`.agents/skills/{name}/SKILL.md`) — step-by-step implementation patterns. Examples: +- Implement a CRUD handler: `read_file` on `.agents/skills/coldbox-handler-development/SKILL.md` +- Build a REST API: `read_file` on `.agents/skills/coldbox-rest-api-development/SKILL.md` +- Write tests: `read_file` on `.agents/skills/coldbox-testing-handler/SKILL.md` + +**Custom Skills** (`.agents/skills-custom/{name}/SKILL.md`) — project-specific patterns. Load by name from `.agents/skills-custom/`. + +**To load any skill or guideline:** use `read_file` on the path shown above or in the inventories below. + +### Available Guidelines + +The following additional guidelines are available for this project. Request them by name when needed: + +No additional module guidelines installed. + +**To load a guideline:** Request it by name when you need detailed framework or module documentation. + +### Available Skills + +The following skills provide step-by-step implementation patterns. Request specific skills when you need detailed how-to instructions: + +**Module Skills:** + +_BoxLang (43):_ +- **boxlang-application-descriptor** - Use this skill when designing or debugging Application.bx behavior: app discover... +- **boxlang-async-programming** - Use this skill when writing BoxLang asynchronous code: BoxFuture, futureNew, asy... +- **boxlang-best-practices** - Use this skill when writing, reviewing, or improving BoxLang code to ensure it f... +- **boxlang-caching** - Use this skill when implementing caching in BoxLang applications: cache provider... +- **boxlang-cfml-migration** - Use this skill when helping developers migrate from CFML (Adobe ColdFusion or Lu... +- **boxlang-classes-and-oop** - Use this skill when writing BoxLang classes, components, interfaces, inheritance... +- **boxlang-code-documenter** - Use this skill when adding documentation comments to BoxLang code: writing funct... +- **boxlang-code-reviewer** - Use this skill when reviewing BoxLang code for quality, correctness, security vu... +- **boxlang-configuration** - Use this skill when configuring BoxLang runtime settings via boxlang.json, setti... +- **boxlang-database-access** - Use this skill when writing BoxLang database code: queryExecute, bx:query, datas... +- **boxlang-deployment** - Use this skill when deploying BoxLang applications: CommandBox server setup, Doc... +- **boxlang-docbox** - Use this skill when generating API documentation for BoxLang or CFML projects wi... +- **boxlang-file-handling** - Use this skill when reading, writing, copying, moving, or deleting files and dir... +- **boxlang-file-watchers** - Use this skill when implementing BoxLang filesystem watchers: watcherNew/watcher... +- **boxlang-functional-programming** - Use this skill when working with BoxLang lambdas, closures, arrow functions, hig... +- **boxlang-interceptors** - Use this skill when working with BoxLang's interceptor/event system: creating in... +- **boxlang-java-integration** - Use this skill when integrating BoxLang with Java: createObject, static method c... +- **boxlang-language-fundamentals** - Use this skill when writing or reviewing BoxLang code covering syntax, file type... +- **boxlang-modules-and-packages** - Use this skill when installing, configuring, or using BoxLang modules: box insta... +- **boxlang-runtime-aws-lambda** - Use this skill when building, deploying, or debugging BoxLang applications on AW... +- **boxlang-runtime-chromebook** - Use this skill when setting up or developing BoxLang on a Chromebook, including ... +- **boxlang-runtime-cli-scripting** - Use this skill when writing BoxLang CLI scripts and classes, handling command-li... +- **boxlang-runtime-commandbox** - Use this skill when deploying BoxLang as an enterprise Java servlet application ... +- **boxlang-runtime-compiled-native-binaries** - Use this skill when compiling BoxLang scripts to standalone native executables u... +- **boxlang-runtime-desktop** - Use this skill when building BoxLang desktop applications with Electron and the ... +- **boxlang-runtime-desktop-electron** - Use this skill when building BoxLang desktop applications with Electron and the ... +- **boxlang-runtime-digitalocean-app** - Use this skill when deploying BoxLang applications to DigitalOcean App Platform ... +- **boxlang-runtime-docker** - Use this skill when containerizing BoxLang applications with Docker, including c... +- **boxlang-runtime-esp32** - Use this skill when deploying BoxLang to ESP32 microcontrollers using MatchBox's... +- **boxlang-runtime-github-actions** - Use this skill when setting up GitHub Actions CI/CD pipelines for BoxLang projec... +- **boxlang-runtime-google-cloud-functions** - Use this skill when building, testing, or deploying BoxLang applications on Goog... +- **boxlang-runtime-jsr-223** - Use this skill when embedding BoxLang into Java applications via the JSR-223 scr... +- **boxlang-runtime-matchbox** - Use this skill when using MatchBox, the Rust-based native implementation of BoxL... +- **boxlang-runtime-miniserver** - Use this skill when running BoxLang as a lightweight web server using the BoxLan... +- **boxlang-runtime-spring-boot** - Use this skill when integrating BoxLang with Spring Boot applications, including... +- **boxlang-runtime-wasm-container** - Use this skill when compiling BoxLang applications to server-side WebAssembly (W... +- **boxlang-runtime-wasm-in-the-browser** - Use this skill when compiling BoxLang to WebAssembly or JavaScript ES modules fo... +- **boxlang-scheduled-tasks** - Use this skill when creating or managing BoxLang scheduled workloads: Scheduler ... +- **boxlang-security** - Use this skill when reviewing BoxLang code or applications for security vulnerab... +- **boxlang-templating** - Use this skill when writing BoxLang markup templates (.bxm files), mixing HTML w... +- **boxlang-testing** - Use this skill when writing, running, or debugging tests for BoxLang application... +- **boxlang-web-development** - Use this skill when building BoxLang web applications: Application.bx lifecycle,... +- **boxlang-zip** - Use this skill when creating, extracting, listing, or modifying ZIP archives in ... + +_CacheBox (1):_ +- **cachebox-standalone** - Use this skill when working with CacheBox as a standalone caching framework (out... + +_ColdBox (29):_ +- **coldbox-ai-integration** - Use this skill when integrating AI capabilities into a ColdBox application using... +- **coldbox-app-layouts** - Use this skill when choosing a ColdBox application layout (flat, boxlang, or mod... +- **coldbox-async-programming** - Use this skill when building async pipelines, working with ColdBox Futures, runn... +- **coldbox-cache-integration** - Use this skill when implementing caching inside a ColdBox application -- configu... +- **coldbox-cli** - Use this skill when using the ColdBox CLI (CommandBox module) to scaffold applic... +- **coldbox-configuration** - Use this skill when configuring a ColdBox application in ColdBox.cfc, setting up... +- **coldbox-decorators** - Use this skill when extending or overriding ColdBox framework internals via the ... +- **coldbox-di** - Use this skill when working with dependency injection inside a ColdBox applicati... +- **coldbox-documenter** - Use this skill when writing or improving documentation comments for ColdBox appl... +- **coldbox-event-model** - Use this skill when working with the ColdBox event object (prc/rc), managing req... +- **coldbox-flash-messaging** - Use this skill when implementing flash RAM messaging in ColdBox, using cbMessage... +- **coldbox-handler-development** - Use this skill when creating ColdBox handlers (controllers), implementing CRUD a... +- **coldbox-interceptor-development** - Use this skill when creating ColdBox interceptors for cross-cutting concerns, li... +- **coldbox-layout-development** - Use this skill when creating ColdBox layouts (master page templates), building a... +- **coldbox-logging** - Use this skill for all ColdBox-specific logging concerns: configuring LogBox ins... +- **coldbox-module-development** - Use this skill when creating reusable ColdBox modules, writing ModuleConfig.cfc,... +- **coldbox-proxy** - Use this skill when building ColdBox Proxy objects to expose ColdBox event handl... +- **coldbox-request-context** - Use this skill when working with the ColdBox RequestContext object (event), mana... +- **coldbox-rest-api-development** - Use this skill when building RESTful APIs in ColdBox using RestHandler, creating... +- **coldbox-reviewer** - Use this skill when reviewing ColdBox application code for correctness, security... +- **coldbox-routing-development** - Use this skill when configuring ColdBox routes, setting up RESTful resource rout... +- **coldbox-scheduled-tasks** - Use this skill when creating ColdBox scheduled tasks, building Scheduler.cfc fil... +- **coldbox-testing-base-classes** - Use this skill to understand which ColdBox testing base class to extend for a gi... +- **coldbox-testing-handler** - Use this skill when testing ColdBox event handlers with execute(), asserting rc/... +- **coldbox-testing-http-methods** - Use this skill when simulating HTTP requests in ColdBox tests using the get(), p... +- **coldbox-testing-integration** - Use this skill when writing integration tests for ColdBox that use real dependen... +- **coldbox-testing-interceptor** - Use this skill when unit testing ColdBox interceptors in isolation using BaseInt... +- **coldbox-testing-model** - Use this skill when unit testing ColdBox model objects (services, repositories, ... +- **coldbox-view-rendering** - Use this skill when rendering views and partials in ColdBox, creating reusable v... + +_CommandBox (11):_ +- **commandbox-config-settings** - Use this skill for CommandBox global configuration: config set/show/clear comman... +- **commandbox-deploying** - Use this skill for deploying CommandBox applications to production: Docker with ... +- **commandbox-developing** - Use this skill for developing CommandBox extensions: creating custom commands (C... +- **commandbox-embedded-server** - Use this skill for the CommandBox embedded server: starting and stopping servers... +- **commandbox-package-management** - Use this skill for CommandBox package management: box.json configuration, instal... +- **commandbox-setup** - Use this skill for installing, configuring, and upgrading CommandBox CLI: Homebr... +- **commandbox-task-runners** - Use this skill for CommandBox task runners: creating task CFCs, targets, passing... +- **commandbox-testing** - Use this skill for CommandBox TestBox integration: testbox run command, running ... +- **commandbox-usage** - Use this skill for CommandBox CLI usage: running commands, namespaces, tab compl... +- **commandbox-boxlang** - Use this skill when configuring CommandBox to run BoxLang server instances, usin... +- **commandbox-migrations** - Use this skill when running database migrations from the CommandBox CLI using co... + +_LogBox (1):_ +- **logbox** - Use this skill whenever working with LogBox -- standalone or inside a ColdBox ap... + +_Other (6):_ +- **ortus-coding-standards** - Use this skill when writing, reviewing, or formatting any Ortus Solutions code (... +- **database-migrations** - Use this skill when managing database schema changes in ColdBox/BoxLang using cf... +- **testing-coverage** - Use this skill when setting up code coverage analysis for ColdBox/ColdFusion/Box... +- **testing-fixtures** - Use this skill when creating test fixtures, factory patterns, or test data build... +- **cbdebugger** - Use this skill when installing, configuring, or using the CBDebugger visual debu... +- **route-visualizer** - Use this skill when inspecting all registered ColdBox routes using the route-vis... + +_TestBox (9):_ +- **testbox-assertions** - Use this skill when using the TestBox $assert object for xUnit-style assertions:... +- **testbox-bdd** - Use this skill when writing BDD-style tests with TestBox using describe/it block... +- **testbox-cbmockdata** - Use this skill when generating realistic fake/mock data in tests using cbMockDat... +- **testbox-expectations** - Use this skill when writing fluent expectations in TestBox using expect(), expec... +- **testbox-listeners** - Use this skill when implementing TestBox run listeners (callbacks): onBundleStar... +- **testbox-mockbox** - Use this skill when creating mocks, stubs, and spies in TestBox using MockBox: c... +- **testbox-reporters** - Use this skill when selecting or configuring TestBox reporters: ANTJunit, Consol... +- **testbox-runners** - Use this skill when running TestBox tests: CommandBox CLI (testbox run), BoxLang... +- **testbox-unit-xunit** - Use this skill when writing xUnit-style tests in TestBox using test functions (t... + +_WireBox (2):_ +- **wirebox-di** - Use this skill when working with WireBox dependency injection -- bootstrapping t... +- **wirebox-aop** - Use this skill when working with WireBox Aspect-Oriented Programming (AOP) -- ac... + +**To load a skill:** Use `read_file` on `.agents/skills/{skill-name}/SKILL.md` (e.g., `.agents/skills/coldbox-handler-development/SKILL.md`) for core skills, or `.agents/skills-custom/{skill-name}/SKILL.md` for custom project skills. + +## Important Notes + +- Framework reinit: Use `?fwreinit=true` or configure `reinitPassword` for production +- Module routes process before app routes - be aware of conflicts +- Use PRC for internal data, RC only for user input +- Always validate user input from RC + +## MCP Documentation Servers + +This project has access to the following Model Context Protocol (MCP) documentation servers for live, up-to-date information: + +**Core Documentation Servers:** + +- **boxlang**: BoxLang Language Documentation - https://ai.ortusbooks.com/~gitbook/mcp +- **coldbox**: ColdBox Framework Documentation - https://coldbox.ortusbooks.com/~gitbook/mcp +- **commandbox**: CommandBox CLI Documentation - https://commandbox.ortusbooks.com/~gitbook/mcp +- **testbox**: TestBox Testing Framework - https://testbox.ortusbooks.com/~gitbook/mcp +- **wirebox**: WireBox Dependency Injection - https://wirebox.ortusbooks.com/~gitbook/mcp +- **cachebox**: CacheBox Caching Framework - https://cachebox.ortusbooks.com/~gitbook/mcp +- **logbox**: LogBox Logging Framework - https://logbox.ortusbooks.com/~gitbook/mcp + +**Module Documentation Servers:** + +- **cfmigrations**: Database Migrations - https://cfmigrations.ortusbooks.com/~gitbook/mcp +- **cbdebugger**: CBDebugger Debugging Tools - https://cbdebugger.ortusbooks.com/~gitbook/mcp + +**Using MCP Servers:** Query these servers when you need current documentation, API references, or code examples. They provide live, up-to-date information directly from official documentation sources. + + + + + +## About This Application + +> ⚠️ Fill in this section to give your AI assistant context about your specific application. + +### Business Domain + + + +### Key Services & Models + + + +### Authentication & Security + + + +### API Endpoints + + + +### Database + + + +### Deployment + + \ No newline at end of file diff --git a/Application.cfc b/Application.cfc index 7dbf3c4734..bf8dcdae6a 100644 --- a/Application.cfc +++ b/Application.cfc @@ -17,10 +17,10 @@ component { * MAKE SURE THIS FILE IS NOT WEB ACCESSIBLE! * Without this, your NON CommandBox ContentBox install will fail. */ - this.cbLoadDynamicEnvironment = false; - this.cbEnvFile = expandPath( "/.env" ); + this.cbLoadDynamicEnvironment = false + this.cbEnvFile = expandPath( "/.env" ) if ( this.cbLoadDynamicEnvironment ) { - loadEnv(); + loadEnv() } /** @@ -28,29 +28,20 @@ component { * Application Properties: Modify as you see fit! * -------------------------------------------------------------------------- */ - this.name = "ContentBox CMS"; - this.sessionManagement = true; - this.sessionTimeout = createTimespan( 0, 1, 0, 0 ); - this.setClientCookies = true; - this.setDomainCookies = true; - this.scriptProtect = false; - this.secureJSON = false; - this.timezone = "UTC"; - - /** - * -------------------------------------------------------------------------- - * Lucee Specific Settings - * -------------------------------------------------------------------------- - */ - + this.name = "ContentBox CMS" + this.sessionManagement = true + this.sessionTimeout = createTimespan( 0, 1, 0, 0 ) + this.setClientCookies = true + this.setDomainCookies = true + this.scriptProtect = false + this.secureJSON = false + this.timezone = "UTC" // buffer the output of a tag/function body to output in case of a exception - this.bufferOutput = true; - // Activate Gzip Compression - this.compression = false; + this.bufferOutput = true // Turn on/off white space management - this.whiteSpaceManagement = "smart"; + this.whiteSpaceManagement = "smart" // Turn on/off remote cfc content whitespace - this.suppressRemoteComponentContent = false; + this.suppressRemoteComponentContent = false /** * -------------------------------------------------------------------------- @@ -58,12 +49,12 @@ component { * -------------------------------------------------------------------------- * Modify only if you need to, else default them. */ - COLDBOX_APP_ROOT_PATH = getDirectoryFromPath( getCurrentTemplatePath() ); - COLDBOX_APP_MAPPING = ""; - COLDBOX_WEB_MAPPING = ""; - COLDBOX_CONFIG_FILE = ""; - COLDBOX_APP_KEY = ""; - COLDBOX_FAIL_FAST = true; + COLDBOX_APP_ROOT_PATH = getDirectoryFromPath( getCurrentTemplatePath() ) + COLDBOX_APP_MAPPING = "" + COLDBOX_WEB_MAPPING = "" + COLDBOX_CONFIG_FILE = "" + COLDBOX_APP_KEY = "" + COLDBOX_FAIL_FAST = true /** * -------------------------------------------------------------------------- @@ -74,10 +65,10 @@ component { * - contentbox : Where the ContentBox module root is installed * - cborm : Where the cborm library is installed: Needed for ORM Event Handling. */ - this.mappings[ "/cbapp" ] = COLDBOX_APP_ROOT_PATH; - this.mappings[ "/coldbox" ] = COLDBOX_APP_ROOT_PATH & "coldbox"; - this.mappings[ "/contentbox" ] = COLDBOX_APP_ROOT_PATH & "modules/contentbox"; - this.mappings[ "/cborm" ] = this.mappings[ "/contentbox" ] & "/modules/contentbox-deps/modules/cborm"; + this.mappings[ "/cbapp" ] = COLDBOX_APP_ROOT_PATH + this.mappings[ "/coldbox" ] = COLDBOX_APP_ROOT_PATH & "lib/coldbox" + this.mappings[ "/contentbox" ] = COLDBOX_APP_ROOT_PATH & "modules/contentbox" + this.mappings[ "/cborm" ] = this.mappings[ "/contentbox" ] & "/modules/contentbox-deps/modules/cborm" /** * -------------------------------------------------------------------------- @@ -87,11 +78,11 @@ component { * - Dialect is incredibly important! Do not let Hibernate auto configur it, you can get nasty errors. * So Make sure you select one. */ - request.cbSystemHelper = new coldbox.system.core.delegates.Env(); + // THE CONTENTBOX DATASOURCE NAME - this.datasource = "contentbox"; + this.datasource = "contentbox" // ORM SETTINGS - this.ormEnabled = true; + this.ormEnabled = true // cfformat-ignore-start this.ormSettings = { // ENTITY LOCATIONS, ADD MORE LOCATIONS AS YOU SEE FIT @@ -106,12 +97,12 @@ component { "modules/contentbox/modules_user" ], // THE DIALECT OF YOUR DATABASE OR LET HIBERNATE FIGURE IT OUT, UP TO YOU TO CONFIGURE. - dialect : request.cbSystemHelper.getSystemSetting( "ORM_DIALECT", "" ), + dialect : _getSystemSetting( "ORM_DIALECT", "" ), dbcreate : "none", - secondarycacheenabled: request.cbSystemHelper.getSystemSetting( "ORM_SECONDARY_CACHE", false ), - cacheprovider : request.cbSystemHelper.getSystemSetting( "ORM_SECONDARY_CACHE", "ehCache" ), - logSQL : request.cbSystemHelper.getSystemSetting( "ORM_LOGSQL", false ), - sqlScript : request.cbSystemHelper.getSystemSetting( "ORM_SQL_SCRIPT", "" ), + secondarycacheenabled: _getSystemSetting( "ORM_SECONDARY_CACHE", false ), + cacheprovider : _getSystemSetting( "ORM_SECONDARY_CACHE", "ehCache" ), + logSQL : _getSystemSetting( "ORM_LOGSQL", false ), + sqlScript : _getSystemSetting( "ORM_SQL_SCRIPT", "" ), // ORM SESSION MANAGEMENT SETTINGS, DO NOT CHANGE flushAtRequestEnd : false, autoManageSession : false, @@ -122,10 +113,10 @@ component { skipCFCWithError : true, // TURN ON FOR Debugging if ORM mappings are not working. savemapping : false - }; + } // cfformat-ignore-end - // applicationStop();abort; + // applicationStop()abort /*****************************************************************************************************/ /************************************** CF APP LISTENERS *********************************************/ @@ -140,9 +131,9 @@ component { COLDBOX_APP_MAPPING, COLDBOX_FAIL_FAST, COLDBOX_WEB_MAPPING - ); - application.cbBootstrap.loadColdbox(); - return true; + ) + application.cbBootstrap.loadColdbox() + return true } boolean function onRequestStart( string targetPage ){ @@ -153,9 +144,9 @@ component { isNull( application.cbController ) ) { if ( this.cbLoadDynamicEnvironment ) { - loadEnv( force: true ); + loadEnv( force: true ) } - reinitApplication(); + reinitApplication() } // Development Reinit + ORM Reloads @@ -167,36 +158,36 @@ component { application.cbBootstrap.isFWReinit() ) { if ( this.cbLoadDynamicEnvironment ) { - loadEnv( force: true ); + loadEnv( force: true ) } - if ( structKeyExists( server, "lucee" ) ) { - pagePoolClear(); + if ( getFunctionList().keyExists( "pagePoolClear" ) ) { + pagePoolClear() } - ormReload(); + ormReload() } // Process ColdBox Request - application.cbBootstrap.onRequestStart( arguments.targetPage ); + application.cbBootstrap.onRequestStart( arguments.targetPage ) - return true; + return true } function onSessionStart(){ if ( !isNull( application.cbBootstrap ) ) { - application.cbBootStrap.onSessionStart(); + application.cbBootStrap.onSessionStart() } } function onSessionEnd( struct sessionScope, struct appScope ){ - arguments.appScope.cbBootStrap.onSessionEnd( argumentCollection = arguments ); + arguments.appScope.cbBootStrap.onSessionEnd( argumentCollection = arguments ) } boolean function onMissingTemplate( template ){ - return application.cbBootstrap.onMissingTemplate( argumentCollection = arguments ); + return application.cbBootstrap.onMissingTemplate( argumentCollection = arguments ) } function onApplicationEnd( struct appScope ){ - arguments.appScope.cbBootstrap.onApplicationEnd( arguments.appScope ); + arguments.appScope.cbBootstrap.onApplicationEnd( arguments.appScope ) } /*****************************************************************************************************/ @@ -207,30 +198,30 @@ component { * Application Reinitialization **/ private void function reinitApplication(){ - onApplicationStart(); + onApplicationStart() } /** * This method is only called if you are in a NON CommandBox install to load the environment variables */ private void function loadEnv( boolean force = false ){ - var javaSystem = createObject( "java", "java.lang.System" ); - var value = javaSystem.getProperty( "contentbox_runtime_env" ); + var javaSystem = createObject( "java", "java.lang.System" ) + var value = javaSystem.getProperty( "contentbox_runtime_env" ) // If not loaded, lock and load. if ( isNull( value ) || arguments.force ) { lock name="contentbox_runtime_env" timeout="15" throwOnTimeout="true" type="exclusive" { // Double lock if ( isNull( javaSystem.getProperty( "contentbox_runtime_env" ) ) || arguments.force ) { // Load .env file - var props = createObject( "java", "java.util.Properties" ).init(); - props.load( createObject( "java", "java.io.FileInputStream" ).init( this.cbEnvFile ) ); + var props = createObject( "java", "java.util.Properties" ).init() + props.load( createObject( "java", "java.io.FileInputStream" ).init( this.cbEnvFile ) ) // Iterate and add - var availableProps = props.propertyNames(); + var availableProps = props.propertyNames() while ( availableProps.hasNext() ) { - var propName = availableProps.next(); - javaSystem.setProperty( propName, props.getProperty( propName ) ); + var propName = availableProps.next() + javaSystem.setProperty( propName, props.getProperty( propName ) ) } - javaSystem.setProperty( "contentbox_runtime_env", true ); + javaSystem.setProperty( "contentbox_runtime_env", true ) } // end double lock } @@ -239,4 +230,24 @@ component { // end lock check } + /** + * Helper to get system settings from either the environment or the java system properties, with an optional default value. + * This is used to configure ORM settings via environment variables, which is especially useful in containerized environments. + * The order of precedence is: Environment Variables > Java System Properties > Default Value + */ + private string function _getSystemSetting( string settingName, any defaultValue = "" ){ + var env = server.system.environment + var properties = server.system.properties + + if ( structKeyExists( env, settingName ) ) { + return env[ settingName ] + } + else if ( structKeyExists( properties, settingName ) ) { + return properties[ settingName ] + } + else { + return defaultValue + } + } + } diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000000..eef4bd20cf --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md \ No newline at end of file diff --git a/box-site.json b/box-site.json index 4a2671be8c..cb77311dbe 100644 --- a/box-site.json +++ b/box-site.json @@ -27,7 +27,7 @@ "Curt Gratz " ], "dependencies":{ - "coldbox":"^7.0.0+7", + "coldbox":"^8", "contentbox":"~@version.number@+@build.number@", "commandbox-boxlang":"*", "commandbox-migrations":"*" @@ -35,6 +35,10 @@ "devDependencies":{ }, "installPaths":{ + "coldbox":"lib/coldbox/" + }, + "installPathConventions":{ + "modules":"lib/modules" }, "ignores":[ ], @@ -42,9 +46,6 @@ "contentbox:install":"install --force && cd modules/contentbox && install --force", "contentbox:migrate" : "migrate up manager=contentbox", "contentbox:migrate:up" : "run-script contentbox:migrate", - "contentbox:migrate:down" : "migrate down manager=contentbox", - "format":"cfformat run config/,handlers/,models/,modules_app/**/*.cfc,Application.cfc --overwrite", - "format:watch":"cfformat watch config/,handlers/,models/,modules_app/**/*.cfc,Application.cfc ./.cfformat.json", - "format:check":"cfformat check config/**/*.cfc,modules_app/**/*.cfc,modules/contentbox/**/*.cfc,tests/**/*.cfc,Application.cfc" + "contentbox:migrate:down" : "migrate down manager=contentbox" } } diff --git a/box.json b/box.json index d73ab48389..6b50718756 100644 --- a/box.json +++ b/box.json @@ -1,6 +1,6 @@ { "name":"ContentBox Tester Site", - "version":"6.3.2", + "version":"7.0.0", "author":"Ortus Solutions ", "shortDescription":"A tester site for developing the ContentBox Modular CMS", "type":"cms", @@ -24,42 +24,41 @@ "Curt Gratz " ], "dependencies":{ - "coldbox":"be", + "coldbox":"^8", "commandbox-migrations":"*" }, "devDependencies":{ "commandbox-boxlang":"*", - "commandbox-cfformat":"*", "commandbox-docbox":"*", "testbox":"*", "cbdebugger":"*", "route-visualizer":"*" }, "installPaths":{ - "testbox":"testbox/", - "coldbox":"coldbox/", - "cbdebugger":"modules/cbdebugger/", - "route-visualizer":"modules/route-visualizer/" + "testbox":"lib/testbox/", + "coldbox":"lib/coldbox/", + "cbdebugger":"lib/modules/cbdebugger/", + "route-visualizer":"lib/modules/route-visualizer/" + }, + "installPathConventions":{ + "modules":"lib/modules" }, "ignores":[], "scripts":{ - "release":"recipe build/release.boxr", "build:allDocs":"task run taskFile=build/BuildDocs.cfc :version=`package show version`", "build:apidocs":"task run taskFile=build/BuildDocs.cfc target=apiDocs :version=`package show version`", "build:swagger":"task run taskFile=build/BuildDocs.cfc target=swagger :version=`package show version`", "dbseed:mysql":"task run contentbox/modules/seeders/MSSQL.cfc", "dbseed:mssal":"task run contentbox/modules/seeders/SeedMySQL.cfc", "dbseed:postgres":"task run contentbox/modules/seeders/SeedPostgreSQL.cfc", - "format":"cfformat run config/**/*.cfc,modules_app/**/*.cfc,modules/contentbox/**/*.cfc,tests/**/*.cfc,Application.cfc --overwrite", - "format:watch":"cfformat watch config/**/*.cfc,modules_app/**/*.cfc,modules/contentbox/**/*.cfc,tests/**/*.cfc,Application.cfc ./.cfformat.json", - "format:watch:core":"cfformat watch config/**/*.cfc,modules/contentbox/models/**/*.cfc,Application.cfc ./.cfformat.json", - "format:check":"cfformat check config/**/*.cfc,modules_app/**/*.cfc,modules/contentbox/**/*.cfc,tests/**/*.cfc,Application.cfc ./.cfformat.json", "contentbox:install":"install --force && cd modules/contentbox && install --force", "contentbox:migrate:create":"migrate create name=${1} manager=contentbox", "contentbox:migrate":"migrate up manager=contentbox", "contentbox:migrate:up":"run-script contentbox:migrate", "contentbox:migrate:down":"migrate down manager=contentbox", - "contentbox:migrate:fresh":"migrate fresh manager=contentbox" + "contentbox:migrate:fresh":"migrate fresh manager=contentbox", + "format":"!boxlang format --source config,handlers,modules/contentbox,tests/specs --excludes modules/contentbox/modules/contentbox-deps", + "format:check":"!boxlang format --check --source config,handlers,modules/contentbox,tests/specs --excludes modules/contentbox/modules/contentbox-deps" }, "testbox":{ "runner":[ diff --git a/build/release.boxr b/build/release.boxr deleted file mode 100755 index a63f2ccdb2..0000000000 --- a/build/release.boxr +++ /dev/null @@ -1,14 +0,0 @@ -# This recipe signifies a new release of the module by doing merges and bumps accordingly - -# Check out master and update it locally -!git checkout -f master -!git pull origin master - -# Merge development into it for release -!git merge --no-ff development - -# Push all branches back out to github -!git push origin --all - -# Check development again -!git checkout -f development diff --git a/changelog.md b/changelog.md index 77535e5d6d..6444018a3f 100644 --- a/changelog.md +++ b/changelog.md @@ -9,9 +9,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +- https://contentbox.ortusbooks.com/readme/release-history/7.0.0 + +### Fixed + +- Site creation now attaches default settings to the new site before persistence so ORM cascades insert the parent site before child settings. + +## [6.3.2] - 2025-12-05 + ### Fixed -* Fixed an issue where different engines were handing defaults +- Fixed an issue where different engines were handing defaults ## [6.3.1] - 2025-10-20 @@ -25,107 +33,109 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Fixed -- CONTENTBOX-1510 - Emails being sanitized and invalidated on Comment form submission +- CONTENTBOX-1510 - Emails being sanitized and invalidated on Comment form submission ## [6.0.4] - 2024-02-20 ### Fixed -- JS Library Patches -- [CONTENTBOX-1509](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1509) `featuredImage` URL on initial migration should be nullable +- JS Library Patches +- [CONTENTBOX-1509](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1509) `featuredImage` URL on initial migration should be nullable ## [6.0.3] - 2024-02-13 ### Updated -- All github actions +- All github actions ### Bugs -- [CONTENTBOX-1507](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1507) BulkSave not accounting for sites when filtering and saving -- [CONTENTBOX-1506](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1506) Updated all server.jsons to use \`env\` for the ortus orm extension since the latest lucee build broken extensions via jvm args -- [CONTENTBOX-1505](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1505) RenderView widget exception when using \`view()\` to render the view +- [CONTENTBOX-1507](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1507) BulkSave not accounting for sites when filtering and saving +- [CONTENTBOX-1506](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1506) Updated all server.jsons to use \`env\` for the ortus orm extension since the latest lucee build broken extensions via jvm args +- [CONTENTBOX-1505](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1505) RenderView widget exception when using \`view()\` to render the view ## [6.0.2] - 2024-01-15 ### Bugs -- [CONTENTBOX-1501](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1501) Init migration needs to verify permissions and roles separately to make sure it passes on created dbs +- [CONTENTBOX-1501](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1501) Init migration needs to verify permissions and roles separately to make sure it passes on created dbs ## [6.0.1] - 2023-12-20 ### Bugs -- [CONTENTBOX-1500](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1500) Defensive coding for permissions migration on new instance +- [CONTENTBOX-1500](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1500) Defensive coding for permissions migration on new instance ## [6.0.0] - 2023-12-18 ### Bugs -- [CONTENTBOX-1323](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1323) Import With Overwrite Throws an Error -- [CONTENTBOX-1370](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1370) UI Disappoints in Menu Manager and Broken ContentMenuItem Functionality -- [CONTENTBOX-1404](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1404) Issue Importing Site using ContentBox 5.03 and a fresh export -- [CONTENTBOX-1406](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1406) Switching Editors Sends Item Being Edited in to Draft Status -- [CONTENTBOX-1427](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1427) CBRequest postRender of AdminBar will throw errors if Buffer is flushed to Browser -- [CONTENTBOX-1428](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1428) Incorrect Site and Parent Re-Assignment When Using Admin Bar Edit -- [CONTENTBOX-1439](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1439) NOW for a new blog post doesn't update the time anymore with the alpine updates -- [CONTENTBOX-1445](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1445) Menu Manager Create new does not working -- [CONTENTBOX-1450](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1450) menu manager sandbox display is broken -- [CONTENTBOX-1453](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1453) modules_user is not currently included in the ormSettings so some contentbox modules on forgebox don't work without Application.cfc being updated by the user -- [CONTENTBOX-1454](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1454) files fail to upload in media manager after server restart -- [CONTENTBOX-1462](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1462) Generated Sitemap has broken links -- [CONTENTBOX-1467](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1467) FeedGenerator.cfc Incompatible with ACF 2018+ -- [CONTENTBOX-1468](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1468) getOpenGraphMeta broken for description -- [CONTENTBOX-1472](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1472) Ensure visibility of Menu Toggle in mobile views -- [CONTENTBOX-1476](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1476) Links do not have enough contrast -- [CONTENTBOX-1481](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1481) Missing Icons -- [CONTENTBOX-1482](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1482) PageInclude/EntryInclude/Menu widgets are not including the current site -- [CONTENTBOX-1484](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1484) Menu Preview Error -- [CONTENTBOX-1496](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1496) checkAll failing due to window scoping issues -- [CONTENTBOX-1498](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1498) Missing fieldset tag -- [CONTENTBOX-1499](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1499) An error is recorded in the log when initialising a custom widget in an add-on module +- [CONTENTBOX-1323](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1323) Import With Overwrite Throws an Error +- [CONTENTBOX-1370](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1370) UI Disappoints in Menu Manager and Broken ContentMenuItem Functionality +- [CONTENTBOX-1404](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1404) Issue Importing Site using ContentBox 5.03 and a fresh export +- [CONTENTBOX-1406](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1406) Switching Editors Sends Item Being Edited in to Draft Status +- [CONTENTBOX-1427](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1427) CBRequest postRender of AdminBar will throw errors if Buffer is flushed to Browser +- [CONTENTBOX-1428](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1428) Incorrect Site and Parent Re-Assignment When Using Admin Bar Edit +- [CONTENTBOX-1439](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1439) NOW for a new blog post doesn't update the time anymore with the alpine updates +- [CONTENTBOX-1445](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1445) Menu Manager Create new does not working +- [CONTENTBOX-1450](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1450) menu manager sandbox display is broken +- [CONTENTBOX-1453](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1453) modules_user is not currently included in the ormSettings so some contentbox modules on forgebox don't work without Application.cfc being updated by the user +- [CONTENTBOX-1454](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1454) files fail to upload in media manager after server restart +- [CONTENTBOX-1462](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1462) Generated Sitemap has broken links +- [CONTENTBOX-1467](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1467) FeedGenerator.cfc Incompatible with ACF 2018+ +- [CONTENTBOX-1468](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1468) getOpenGraphMeta broken for description +- [CONTENTBOX-1472](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1472) Ensure visibility of Menu Toggle in mobile views +- [CONTENTBOX-1476](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1476) Links do not have enough contrast +- [CONTENTBOX-1481](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1481) Missing Icons +- [CONTENTBOX-1482](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1482) PageInclude/EntryInclude/Menu widgets are not including the current site +- [CONTENTBOX-1484](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1484) Menu Preview Error +- [CONTENTBOX-1496](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1496) checkAll failing due to window scoping issues +- [CONTENTBOX-1498](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1498) Missing fieldset tag +- [CONTENTBOX-1499](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1499) An error is recorded in the log when initialising a custom widget in an add-on module ### New Features -- [CONTENTBOX-1270](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1270) ContentBox Content Templates -- [CONTENTBOX-1377](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1377) Add Child Layout Property to Pages -- [CONTENTBOX-1451](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1451) use onServerInstall migration scripts from latest CommandBox on server scripts -- [CONTENTBOX-1477](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1477) Upgrade to ColdBox 7 -- [CONTENTBOX-1480](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1480) cfconfig definitions additions to the server definitions -- [CONTENTBOX-1487](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1487) Ability to define domain aliases for sites for domain detection -- [CONTENTBOX-1491](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1491) Migration to cfmigrations for full database and seeding creations instead of ORM -- [CONTENTBOX-1492](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1492) Added the cors module to the site since we have API deployments now -- [CONTENTBOX-1497](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1497) New Content Editing Focus mode to remove distractions -- [CONTENTBOX-1452](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1452) Convert File Operations to cbfs +- [CONTENTBOX-1270](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1270) ContentBox Content Templates +- [CONTENTBOX-1377](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1377) Add Child Layout Property to Pages +- [CONTENTBOX-1451](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1451) use onServerInstall migration scripts from latest CommandBox on server scripts +- [CONTENTBOX-1477](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1477) Upgrade to ColdBox 7 +- [CONTENTBOX-1480](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1480) cfconfig definitions additions to the server definitions +- [CONTENTBOX-1487](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1487) Ability to define domain aliases for sites for domain detection +- [CONTENTBOX-1491](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1491) Migration to cfmigrations for full database and seeding creations instead of ORM +- [CONTENTBOX-1492](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1492) Added the cors module to the site since we have API deployments now +- [CONTENTBOX-1497](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1497) New Content Editing Focus mode to remove distractions +- [CONTENTBOX-1452](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1452) Convert File Operations to cbfs ### Improvements -- [CONTENTBOX-721](https://ortussolutions.atlassian.net/browse/CONTENTBOX-721) Menu Manager Improvements -- [CONTENTBOX-1296](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1296) Add historical slug storage and automatic redirects -- [CONTENTBOX-1399](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1399) Editors Should Have the Ability to Evict Content Cache with new permission: RELOAD_CACHES -- [CONTENTBOX-1429](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1429) Sitemap Search in Admin is extremely slow on large sites. -- [CONTENTBOX-1447](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1447) Logical Groupings for Content Template Form Fields -- [CONTENTBOX-1448](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1448) Move Global Content Template Assignment Up to Template List -- [CONTENTBOX-1455](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1455) 'Remove All' button is displayed under Blog > Custom Fields even when there are no custom fields defined. -- [CONTENTBOX-1458](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1458) Remove content returnformats for pdf to avoid server and bot attacks -- [CONTENTBOX-1469](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1469) Improve position of the menu toggle -- [CONTENTBOX-1474](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1474) Enhance logo quality -- [CONTENTBOX-1488](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1488) latest logins should only be displayed if the tracker is enabled -- [CONTENTBOX-1489](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1489) SEO for meta data on home page, needs to follow site rules instead of page only rules -- [CONTENTBOX-1490](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1490) Removed moment js to luxon for increased support and viability -- [CONTENTBOX-1494](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1494) When using hierarchical slugs on the contentstore and pages the api does not work for retreiveing the right slug due to CF decoding of encoded slugs +- [CONTENTBOX-721](https://ortussolutions.atlassian.net/browse/CONTENTBOX-721) Menu Manager Improvements +- [CONTENTBOX-1296](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1296) Add historical slug storage and automatic redirects +- [CONTENTBOX-1399](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1399) Editors Should Have the Ability to Evict Content Cache with new permission: RELOAD_CACHES +- [CONTENTBOX-1429](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1429) Sitemap Search in Admin is extremely slow on large sites. +- [CONTENTBOX-1447](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1447) Logical Groupings for Content Template Form Fields +- [CONTENTBOX-1448](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1448) Move Global Content Template Assignment Up to Template List +- [CONTENTBOX-1455](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1455) 'Remove All' button is displayed under Blog > Custom Fields even when there are no custom fields defined. +- [CONTENTBOX-1458](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1458) Remove content returnformats for pdf to avoid server and bot attacks +- [CONTENTBOX-1469](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1469) Improve position of the menu toggle +- [CONTENTBOX-1474](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1474) Enhance logo quality +- [CONTENTBOX-1488](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1488) latest logins should only be displayed if the tracker is enabled +- [CONTENTBOX-1489](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1489) SEO for meta data on home page, needs to follow site rules instead of page only rules +- [CONTENTBOX-1490](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1490) Removed moment js to luxon for increased support and viability +- [CONTENTBOX-1494](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1494) When using hierarchical slugs on the contentstore and pages the api does not work for retreiveing the right slug due to CF decoding of encoded slugs ### Tasks -- [CONTENTBOX-1172](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1172) Migrate UI development from bower/grunt to npm/elixir -- [CONTENTBOX-1321](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1321) Convert from Yarn to NPM for package management -- [CONTENTBOX-1470](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1470) Update Panels Styles -- [CONTENTBOX-1471](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1471) Update Tabs Styles -- [CONTENTBOX-1473](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1473) Update Sidebar Styles -- [CONTENTBOX-1478](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1478) Remove old tuckey urlrewrite.xml as this is now in the CommandBox Core -- [CONTENTBOX-1493](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1493) ContentBox Express removed since we now have CommandBox +- [CONTENTBOX-1172](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1172) Migrate UI development from bower/grunt to npm/elixir +- [CONTENTBOX-1321](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1321) Convert from Yarn to NPM for package management +- [CONTENTBOX-1470](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1470) Update Panels Styles +- [CONTENTBOX-1471](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1471) Update Tabs Styles +- [CONTENTBOX-1473](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1473) Update Sidebar Styles +- [CONTENTBOX-1478](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1478) Remove old tuckey urlrewrite.xml as this is now in the CommandBox Core +- [CONTENTBOX-1493](https://ortussolutions.atlassian.net/browse/CONTENTBOX-1493) ContentBox Express removed since we now have CommandBox + +[Unreleased]: https://github.com/Ortus-Solutions/ContentBox/compare/v6.3.2...HEAD -[Unreleased]: https://github.com/Ortus-Solutions/ContentBox/compare/v6.3.1...HEAD +[6.3.2]: https://github.com/Ortus-Solutions/ContentBox/compare/v6.3.1...v6.3.2 [6.3.1]: https://github.com/Ortus-Solutions/ContentBox/compare/v6.3.0...v6.3.1 diff --git a/config/Application.cfm b/config/Application.cfm index e3e4397a3c..7e1e736bef 100755 --- a/config/Application.cfm +++ b/config/Application.cfm @@ -1,5 +1,4 @@ - +******************************************************************************** ---> \ No newline at end of file diff --git a/config/CacheBox.cfc b/config/CacheBox.cfc index afa2e9eb34..4eb5057bc1 100755 --- a/config/CacheBox.cfc +++ b/config/CacheBox.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -10,13 +10,13 @@ component { /** * Configure CacheBox for ColdBox Application Operation */ - function configure(){ + function configure() { /** * -------------------------------------------------------------------------- * CacheBox Configuration (https://cachebox.ortusbooks.com) * -------------------------------------------------------------------------- */ - cacheBox = { + variables.cacheBox = { /** * -------------------------------------------------------------------------- * Default Cache Configuration @@ -25,17 +25,17 @@ component { * It also has a default provider of cachebox which cannot be changed. * All timeouts are in minutes */ - defaultCache : { - objectDefaultTimeout : 120, // two hours default - objectDefaultLastAccessTimeout : 30, // 30 minutes idle time - useLastAccessTimeouts : true, - reapFrequency : 5, - freeMemoryPercentageThreshold : 0, - evictionPolicy : "LRU", - evictCount : 5, - maxObjects : 5000, - objectStore : "ConcurrentStore", // guaranteed objects - coldboxEnabled : true + defaultCache: { + objectDefaultTimeout : 120, // two hours default + objectDefaultLastAccessTimeout: 30, // 30 minutes idle time + useLastAccessTimeouts : true, + reapFrequency : 5, + freeMemoryPercentageThreshold : 0, + evictionPolicy : "LRU", + evictCount : 5, + maxObjects : 5000, + objectStore : "ConcurrentStore", // guaranteed objects + coldboxEnabled : true }, /** * -------------------------------------------------------------------------- @@ -44,7 +44,7 @@ component { * You can use this section to register different cache regions and map them * to different cache providers */ - caches : { + caches: { /** * -------------------------------------------------------------------------- * ColdBox Template Cache @@ -52,18 +52,18 @@ component { * The ColdBox Template cache region is used for event/view caching and * other internal facilities that might require a more elastic cache. */ - template : { - provider : "coldbox.system.cache.providers.CacheBoxColdBoxProvider", - properties : { - objectDefaultTimeout : 120, - objectDefaultLastAccessTimeout : 30, - useLastAccessTimeouts : true, - freeMemoryPercentageThreshold : 0, - reapFrequency : 5, - evictionPolicy : "LRU", - evictCount : 5, - maxObjects : 5000, - objectStore : "ConcurrentSoftReferenceStore" // memory sensitive + template: { + provider : "coldbox.system.cache.providers.CacheBoxColdBoxProvider", + properties: { + objectDefaultTimeout : 120, + objectDefaultLastAccessTimeout: 30, + useLastAccessTimeouts : true, + freeMemoryPercentageThreshold : 0, + reapFrequency : 5, + evictionPolicy : "LRU", + evictCount : 5, + maxObjects : 5000, + objectStore : "ConcurrentSoftReferenceStore" // memory sensitive } }, /** @@ -73,22 +73,22 @@ component { * Sessions are managed by CacheBox and not CFML so we can distribute to any * cache provider. */ - sessions : { - provider : "coldbox.system.cache.providers.CacheBoxColdBoxProvider", - properties : { - objectDefaultTimeout : 60, - objectDefaultLastAccessTimeout : 0, - useLastAccessTimeouts : false, - freeMemoryPercentageThreshold : 0, - reapFrequency : 5, - evictionPolicy : "LRU", - evictCount : 5, - maxObjects : 5000, // Can support up to 5000 user sessions concurrently. Modify if needed. 0 = unlimited - objectStore : "ConcurrentStore" + sessions: { + provider : "coldbox.system.cache.providers.CacheBoxColdBoxProvider", + properties: { + objectDefaultTimeout : 60, + objectDefaultLastAccessTimeout: 0, + useLastAccessTimeouts : false, + freeMemoryPercentageThreshold : 0, + reapFrequency : 5, + evictionPolicy : "LRU", + evictCount : 5, + maxObjects : 5000, // Can support up to 5000 user sessions concurrently. Modify if needed. 0 = unlimited + objectStore : "ConcurrentStore" } } } }; } -} +} \ No newline at end of file diff --git a/config/Coldbox.cfc b/config/Coldbox.cfc index de97ab4d2e..8bf0cb469d 100755 --- a/config/Coldbox.cfc +++ b/config/Coldbox.cfc @@ -8,7 +8,7 @@ component { // Configure Application - function configure(){ + function configure() { /** * -------------------------------------------------------------------------- * ColdBox Directives @@ -18,44 +18,44 @@ component { * you create the appropriate functions and define the environment in your .env or * in the `environments` struct. */ - coldbox = { + variables.coldbox = { // Application Setup - appName : getSystemSetting( "APPNAME", "ContentBox Modular CMS" ), - eventName : "event", + appName : getSystemSetting( "APPNAME", "ContentBox Modular CMS" ), + eventName : "event", // Development Settings - reinitPassword : getSystemSetting( "COLDBOX_REINITPASSWORD", "@fwPassword@" ), - reinitKey : "fwreinit", - handlersIndexAutoReload : false, + reinitPassword : getSystemSetting( "COLDBOX_REINITPASSWORD", "@fwPassword@" ), + reinitKey : "fwreinit", + handlersIndexAutoReload : false, // Implicit Events - defaultEvent : "Main.index", - requestStartHandler : "", - requestEndHandler : "", - applicationStartHandler : "", - applicationEndHandler : "", - sessionStartHandler : "", - sessionEndHandler : "", - missingTemplateHandler : "", + defaultEvent : "Main.index", + requestStartHandler : "", + requestEndHandler : "", + applicationStartHandler : "", + applicationEndHandler : "", + sessionStartHandler : "", + sessionEndHandler : "", + missingTemplateHandler : "", // Extension Points - applicationHelper : "", - viewsHelper : "", - modulesExternalLocation : [], - viewsExternalLocation : "", - layoutsExternalLocation : "", - handlersExternalLocation : "", - requestContextDecorator : "", - controllerDecorator : "", + applicationHelper : "", + viewsHelper : "", + modulesExternalLocation : [ "/lib/modules" ], + viewsExternalLocation : "", + layoutsExternalLocation : "", + handlersExternalLocation: "", + requestContextDecorator : "", + controllerDecorator : "", // Error/Exception Handling - exceptionHandler : "", - invalidEventHandler : "", - customErrorTemplate : "", + exceptionHandler : "", + invalidEventHandler : "", + customErrorTemplate : "", // Application Aspects - handlerCaching : true, - eventCaching : true, - viewCaching : true, + handlerCaching : true, + eventCaching : true, + viewCaching : true, // Will automatically do a mapDirectory() on your `models` for you. - autoMapModels : true, + autoMapModels : true, // Auto converts a json body payload into the RC - jsonPayloadToRC : true + jsonPayloadToRC : true }; /** @@ -63,7 +63,7 @@ component { * Custom Settings * -------------------------------------------------------------------------- */ - settings = {}; + variables.settings = {}; /** * -------------------------------------------------------------------------- @@ -76,20 +76,20 @@ component { * * Uncomment to use, but make sure your .env ENVIRONMENT key is also removed. */ - environments = { development : "localhost" }; + variables.environments = { development: "localhost" }; /** * -------------------------------------------------------------------------- * Logging Directives * -------------------------------------------------------------------------- */ - logBox = { + variables.logBox = { // Define Appenders - appenders : { coldboxTracer : { class : "coldbox.system.logging.appenders.ConsoleAppender" } }, + appenders: { coldboxTracer: { class: "coldbox.system.logging.appenders.ConsoleAppender" } }, // Root Logger - root : { levelmax : "INFO", appenders : "*" }, + root : { levelmax: "INFO", appenders: "*" }, // Implicit Level Categories - info : [ "coldbox.system", "contentbox" ] + info : [ "coldbox.system", "contentbox"] }; /** @@ -97,14 +97,14 @@ component { * Layout Settings * -------------------------------------------------------------------------- */ - layoutSettings = { defaultLayout : "", defaultView : "" }; + variables.layoutSettings = { defaultLayout: "", defaultView: "" }; /** * -------------------------------------------------------------------------- * Custom Interception Points * -------------------------------------------------------------------------- */ - interceptorSettings = { customInterceptionPoints : [] }; + variables.interceptorSettings = { customInterceptionPoints: [] }; /** * -------------------------------------------------------------------------- @@ -112,7 +112,7 @@ component { * -------------------------------------------------------------------------- * Remember that the order of declaration is the order they will be registered and fired */ - interceptors = []; + variables.interceptors = []; /** * -------------------------------------------------------------------------- @@ -120,13 +120,13 @@ component { * -------------------------------------------------------------------------- * The available scopes are : session, client, cluster, cache, or a full instantiation CFC path */ - flash = { - scope : "cache", - properties : { cacheName : "template" }, - inflateToRC : true, // automatically inflate flash data into the RC scope - inflateToPRC : false, // automatically inflate flash data into the PRC scope - autoPurge : true, // automatically purge flash data for you - autoSave : true // automatically save flash scopes at end of a request and on relocations. + variables.flash = { + scope : "cache", + properties : { cacheName: "template" }, + inflateToRC : true, // automatically inflate flash data into the RC scope + inflateToPRC: false, // automatically inflate flash data into the PRC scope + autoPurge : true, // automatically purge flash data for you + autoSave : true // automatically save flash scopes at end of a request and on relocations. }; /** @@ -142,13 +142,13 @@ component { * * } */ - moduleSettings = {}; + variables.moduleSettings = {}; } /** * Testing Mode. */ - function testing(){ + function testing() { development(); } @@ -156,27 +156,29 @@ component { * Development environment * ORTUS DEVELOPMENT ENVIRONMENT, REMOVE FOR YOUR APP IF NEEDED */ - function development(){ - coldbox.handlersIndexAutoReload = true; - coldbox.handlerCaching = false; - coldbox.debugMode = true; - coldbox.reinitpassword = ""; - coldbox.customErrorTemplate = "/coldbox/system/exceptions/Whoops.cfm"; + function development() { + variables.coldbox.handlersIndexAutoReload = true; + variables.coldbox.handlerCaching = false; + variables.coldbox.debugMode = true; + variables.coldbox.reinitpassword = ""; + variables.coldbox.customErrorTemplate = "/coldbox/system/exceptions/Whoops.cfm"; // No Singletons for easy testing - wirebox = { - // singletonReload : true - }; + // variables.wirebox = {// singletonReload : true}; // debugging file - logbox.appenders.files = { - class : "coldbox.system.logging.appenders.RollingFileAppender", - properties : { - filename : "contentbox", - filePath : "/cbapp/config/logs/app" + variables + .logbox + .appenders + .files = { + class : "coldbox.system.logging.appenders.RollingFileAppender", + properties: { + filename: "contentbox", + filePath: "/cbapp/config/logs/app" } }; + // Specific Debugging + Logging // logbox.debug = [ "cbsecurity" ]; // logbox.debug = [ "coldbox.system.web.services" ]; @@ -184,4 +186,4 @@ component { // logbox.debug = [ "root" ]; } -} +} \ No newline at end of file diff --git a/config/Router.cfc b/config/Router.cfc index 13457821b6..098c3c8a1e 100644 --- a/config/Router.cfc +++ b/config/Router.cfc @@ -7,7 +7,7 @@ */ component { - function configure(){ + function configure() { // Configuration setValidExtensions( "xml,json,jsont,rss,html,htm,cfm,print,pdf,doc,txt" ); // Process Full Rewrites then true, else false and an `index.cfm` will always be included in URLs @@ -27,4 +27,4 @@ component { route( ":handler/:action" ).end(); } -} +} \ No newline at end of file diff --git a/config/Scheduler.cfc b/config/Scheduler.cfc index edeea671ff..21ce18d4ad 100644 --- a/config/Scheduler.cfc +++ b/config/Scheduler.cfc @@ -3,7 +3,7 @@ component { /** * Configure the ColdBox Scheduler */ - function configure(){ + function configure() { /** * -------------------------------------------------------------------------- * Configuration Methods @@ -13,8 +13,6 @@ component { * - setExecutor( executorObject ) : change the executor if needed */ - - /** * -------------------------------------------------------------------------- * Register Scheduled Tasks @@ -27,13 +25,14 @@ component { /** * Called before the scheduler is going to be shutdown */ - function onShutdown(){ + function onShutdown() { + } /** * Called after the scheduler has registered all schedules */ - function onStartup(){ + function onStartup() { log.info( "√ ColdBox Core Scheduler started successfully!" ); } @@ -43,11 +42,11 @@ component { * @task The task that got executed * @exception The ColdFusion exception object */ - function onAnyTaskError( required task, required exception ){ + function onAnyTaskError( required task, required exception ) { log.error( - "The global task (#arguments.task.getname()#) failed to executed. Caused by: #exception.message & exception.detail#", - exception.stacktrace - ); + "The global task (#arguments.task.getname()#) failed to executed. Caused by: #exception.message & exception.detail#", + exception.stacktrace + ); } /** @@ -56,11 +55,11 @@ component { * @task The task that got executed * @result The result (if any) that the task produced */ - function onAnyTaskSuccess( required task, result ){ + function onAnyTaskSuccess( required task, result ) { log.info( - "Global task (#arguments.task.getName()#) completed succesfully in #arguments.task.getStats().lastExecutionTime# ms", - arguments.task.getStats() - ); + "Global task (#arguments.task.getName()#) completed succesfully in #arguments.task.getStats().lastExecutionTime# ms", + arguments.task.getStats() + ); } /** @@ -68,8 +67,10 @@ component { * * @task The task about to be executed */ - function beforeAnyTask( required task ){ - log.info( "Starting to execute global task (#arguments.task.getName()#)..." ); + function beforeAnyTask( required task ) { + log.info( + "Starting to execute global task (#arguments.task.getName()#)..." + ); } /** @@ -78,7 +79,8 @@ component { * @task The task that got executed * @result The result (if any) that the task produced */ - function afterAnyTask( required task, result ){ + function afterAnyTask( required task, result ) { + } -} +} \ No newline at end of file diff --git a/config/WireBox.cfc b/config/WireBox.cfc index e8b80d7a67..21ca1ccf5a 100755 --- a/config/WireBox.cfc +++ b/config/WireBox.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -10,40 +10,37 @@ component extends="coldbox.system.ioc.config.Binder" { /** * Configure WireBox, that's it! */ - function configure(){ + function configure() { /** * -------------------------------------------------------------------------- * WireBox Configuration (https://wirebox.ortusbooks.com) * -------------------------------------------------------------------------- * Configure WireBox */ - wireBox = { + variables.wireBox = { // Scope registration, automatically register a wirebox injector instance on any CF scope // By default it registeres itself on application scope - scopeRegistration : { - enabled : true, - scope : "application", // server, cluster, session, application - key : "wireBox" + scopeRegistration: { + enabled: true, + scope : "application", // server, cluster, session, application + key : "wireBox" }, // DSL Namespace registrations - customDSL : { - // namespace = "mapping name" - }, + // customDSL : {namespace = "mapping name"}, // Custom Storage Scopes - customScopes : { - // annotationName = "mapping name" - }, + // customScopes : { annotationName = "mapping name"}, // Package scan locations - scanLocations : [], + scanLocations : [], // Stop Recursions - stopRecursions : [], + stopRecursions: [], // Parent Injector to assign to the configured injector, this must be an object reference - parentInjector : "", + parentInjector: "", // Register all event listeners here, they are created in the specified order - listeners : [ { class : "coldbox.system.aop.Mixer" } ] + listeners : [ { class: "coldbox.system.aop.Mixer" }] }; + // Map Bindings below } -} +} \ No newline at end of file diff --git a/config/modules/HTMLHelper.cfc b/config/modules/HTMLHelper.cfc index 9ba02a313b..396bd2c748 100644 --- a/config/modules/HTMLHelper.cfc +++ b/config/modules/HTMLHelper.cfc @@ -1,6 +1,6 @@ component { - function configure(){ + function configure() { /** * -------------------------------------------------------------------------- * ColdBox HTML Helper Settings @@ -8,12 +8,12 @@ component { */ return { // The base path of JS assets - js_path : "", + js_path : "", // The base path of CSS assets - css_path : "", + css_path : "", // Encode values on all dynamically generated tags in the HTML Helper - encodeValues : false + encodeValues: false }; } -} +} \ No newline at end of file diff --git a/config/modules/cbdebugger.cfc b/config/modules/cbdebugger.cfc index 78bd8139e4..6e1f478da4 100644 --- a/config/modules/cbdebugger.cfc +++ b/config/modules/cbdebugger.cfc @@ -1,102 +1,103 @@ component { - function configure(){ + function configure() { return { // This flag enables/disables the tracking of request data to our storage facilities // To disable all tracking, turn this master key off - enabled : getSystemSetting( "CBDEBUGGER_ENABLED", false ), + enabled : getSystemSetting( "CBDEBUGGER_ENABLED", false ), // This setting controls if you will activate the debugger for visualizations ONLY // The debugger will still track requests even in non debug mode. - debugMode : true, + debugMode : true, // The URL password to use to activate it on demand - debugPassword : "cb", + debugPassword : "cb", // This flag enables/disables the end of request debugger panel docked to the bottem of the page. // If you disable i, then the only way to visualize the debugger is via the `/cbdebugger` endpoint - requestPanelDock : true, + requestPanelDock: true, // Request Tracker Options - requestTracker : { - storage : "memory", - cacheName : "template", - trackDebuggerEvents : false, + requestTracker : { + storage : "memory", + cacheName : "template", + trackDebuggerEvents : false, // Expand by default the tracker panel or not - expanded : true, + expanded : true, // Slow request threshold in milliseconds, if execution time is above it, we mark those transactions as red - slowExecutionThreshold : 1000, + slowExecutionThreshold : 1000, // How many tracking profilers to keep in stack: Default is to monitor the last 20 requests - maxProfilers : 50, + maxProfilers : 50, // If enabled, the debugger will monitor the creation time of CFC objects via WireBox - profileWireBoxObjectCreation : false, + profileWireBoxObjectCreation: false, // Profile model objects annotated with the `profile` annotation - profileObjects : false, + profileObjects : false, // If enabled, will trace the results of any methods that are being profiled - traceObjectResults : false, + traceObjectResults : false, // Profile Custom or Core interception points - profileInterceptions : false, + profileInterceptions : false, // By default all interception events are excluded, you must include what you want to profile - includedInterceptions : [], + includedInterceptions : [], // Control the execution timers - executionTimers : { - expanded : true, + executionTimers : { + expanded : true, // Slow transaction timers in milliseconds, if execution time of the timer is above it, we mark it - slowTimerThreshold : 250 + slowTimerThreshold: 250 }, // Control the coldbox info reporting - coldboxInfo : { expanded : true }, + coldboxInfo: { expanded: true }, // Control the http request reporting - httpRequest : { - expanded : false, + httpRequest: { + expanded : false, // If enabled, we will profile HTTP Body content, disabled by default as it contains lots of data - profileHTTPBody : true + profileHTTPBody: true } }, // ColdBox Tracer Appender Messages - tracers : { enabled : false, expanded : false }, + tracers : { enabled: false, expanded: false }, // Request Collections Reporting - collections : { + collections: { // Enable tracking - enabled : false, + enabled : false, // Expanded panel or not - expanded : false, + expanded : false, // How many rows to dump for object collections - maxQueryRows : 50, + maxQueryRows: 50, // How many levels to output on dumps for objects - maxDumpTop : 5 + maxDumpTop : 5 }, // CacheBox Reporting - cachebox : { enabled : false, expanded : false }, + cachebox: { enabled: false, expanded: false }, // Modules Reporting - modules : { enabled : true, expanded : false }, + modules : { enabled: true, expanded: false }, // Quick and QB Reporting - qb : { - enabled : false, - expanded : false, + qb : { + enabled : false, + expanded : false, // Log the binding parameters - logParams : true + logParams: true }, // cborm Reporting - cborm : { - enabled : true, - expanded : false, + cborm: { + enabled : true, + expanded : false, // Log the binding parameters - logParams : false + logParams: false }, // Adobe ColdFusion SQL Collector - acfSql : { enabled : false, expanded : false, logParams : true }, + acfSql : { enabled: false, expanded: false, logParams: true }, // Lucee SQL Collector - luceeSQL : { enabled : false, expanded : false, logParams : true }, + luceeSQL: { enabled: false, expanded: false, logParams: true }, // Async Manager Collector - async : { enabled : true, expanded : false }, + async : { enabled: true, expanded: false }, // Hyper Collector - hyper : { - enabled : false, - expanded : false, - logResponseData : false, - logRequestBody : false + hyper : { + enabled : false, + expanded : false, + logResponseData: false, + logRequestBody : false } }; } - function development( settings ){ + function development( settings ) { + } -} +} \ No newline at end of file diff --git a/config/modules/cbfs.cfc b/config/modules/cbfs.cfc index 60e371e189..d700da5223 100644 --- a/config/modules/cbfs.cfc +++ b/config/modules/cbfs.cfc @@ -1,6 +1,6 @@ component { - function configure(){ + function configure() { /** * -------------------------------------------------------------------------- * CBFS Module Settings @@ -9,21 +9,20 @@ component { */ return { // The default disk - "defaultDisk" : "contentbox", + "defaultDisk": "contentbox", // Register the disks on the system - "disks" : { + "disks" : { // Your default application storage - "contentbox" : { - provider : "Local", - properties : { - path : "#controller.getAppRootPath()#modules_app/contentbox-custom/_content", - diskUrl : function(){ - return application.wirebox + "contentbox": { + provider : "Local", + properties: { + path : "#controller.getAppRootPath()#modules_app/contentbox-custom/_content", + diskUrl: function() { + return application + .wirebox .getInstance( "CBHelper@contentBox" ) .site() - .getSiteRoot() - & - "/modules_app/contentbox-custom/_content/" + .getSiteRoot() & "/modules_app/contentbox-custom/_content/"; } } } @@ -31,4 +30,4 @@ component { }; } -} +} \ No newline at end of file diff --git a/config/modules/cbmailservices.cfc b/config/modules/cbmailservices.cfc index 98264809cd..a803fc9779 100644 --- a/config/modules/cbmailservices.cfc +++ b/config/modules/cbmailservices.cfc @@ -1,6 +1,6 @@ component { - function configure(){ + function configure() { /** * -------------------------------------------------------------------------- * ColdBox MailServices @@ -9,24 +9,22 @@ component { */ return { // The default token Marker Symbol - tokenMarker : "@", + tokenMarker : "@", // Default protocol to use, it must be defined in the mailers configuration - defaultProtocol : "files", + defaultProtocol: "files", // Here you can register one or many mailers by name - mailers : { - "default" : { class : "CFMail" }, - "files" : { - class : "File", - properties : { filePath : "config/logs/mail" } + mailers : { + "default": { class: "CFMail" }, + "files" : { + class : "File", + properties: { filePath: "config/logs/mail" } } }, // The defaults for all mail config payloads and protocols - defaults : { - // from : "", - }, + defaults : {}, // Whether the scheduled task is running or not - runQueueTask : true + runQueueTask: true }; } -} +} \ No newline at end of file diff --git a/config/modules/cborm.cfc b/config/modules/cborm.cfc index aeb97c08a5..8487e638a2 100644 --- a/config/modules/cborm.cfc +++ b/config/modules/cborm.cfc @@ -1,6 +1,6 @@ component { - function configure(){ + function configure() { /** * -------------------------------------------------------------------------- * ColdBox ORM @@ -8,25 +8,25 @@ component { * ColdBox cborm configurations https://forgebox.io/view/cborm */ return { - injection : { + injection: { // enable entity injection via WireBox - enabled : true, + enabled: true, // Which entities to include in DI ONLY, if empty include all entities - include : "", + include: "", // Which entities to exclude from DI, if empty, none are excluded - exclude : "" + exclude: "" }, - resources : { + resources: { // Enable the ORM Resource Event Loader - eventLoader : true, + eventLoader : true, // Prefix to use on all the registered pre/post{Entity}{Action} events - eventPrefix : "cb_", + eventPrefix : "cb_", // Pagination max rows - maxRows : 25, + maxRows : 25, // Pagination max row limit: 0 = no limit - maxRowsLimit : 500 + maxRowsLimit: 500 } }; } -} +} \ No newline at end of file diff --git a/config/modules/cbsecurity.cfc b/config/modules/cbsecurity.cfc index 65c7cf67c5..02d3526ce7 100644 --- a/config/modules/cbsecurity.cfc +++ b/config/modules/cbsecurity.cfc @@ -1,6 +1,6 @@ component { - function configure(){ + function configure() { /** * -------------------------------------------------------------------------- * ColdBox Security Configuration @@ -20,46 +20,46 @@ component { * - basicAuth : Leverages basic authentication and basic in-memory user registration in our configuration * - custom : Any other service that adheres to our IAuthService interface */ - authentication : { + authentication: { // The WireBox ID of the authentication service to use which must adhere to the cbsecurity.interfaces.IAuthService interface. - "provider" : "SecurityService@contentbox", + "provider" : "SecurityService@contentbox", // WireBox ID of the user service to use when leveraging user authentication, we default this to whatever is set // by cbauth or basic authentication. (Optional) - "userService" : "AuthorService@contentbox", + "userService" : "AuthorService@contentbox", // The name of the variable to use to store an authenticated user in prc scope on all incoming authenticated requests - "prcUserVariable" : "oCurrentAuthor" + "prcUserVariable": "oCurrentAuthor" }, - firewall : { + firewall: { // Enable annotation security as well - "handlerAnnotationSecurity" : true, + "handlerAnnotationSecurity" : true, // The global invalid authentication event or URI or URL to go if an invalid authentication occurs - "invalidAuthenticationEvent" : "", + "invalidAuthenticationEvent" : "", // Default Auhtentication Action: override or redirect when a user has not logged in - "defaultAuthenticationAction" : "redirect", + "defaultAuthenticationAction": "redirect", // The global invalid authorization event or URI or URL to go if an invalid authorization occurs - "invalidAuthorizationEvent" : "", + "invalidAuthorizationEvent" : "", // Default Authorization Action: override or redirect when a user does not have enough permissions to access something - "defaultAuthorizationAction" : "redirect", + "defaultAuthorizationAction" : "redirect", // You can define your security rules here or externally via a source // specify an array for inline, or a string (db|json|xml|model) for externally - "rules" : { + "rules" : { // Use regex in rules - "useRegex" : true, + "useRegex": true, // Use SSL: Determined by Request - "useSSL" : false, + "useSSL" : false, // A collection of default name-value pairs to add to ALL rules // This way you can add global roles, permissions, redirects, etc - "defaults" : {}, + "defaults": {}, // You can store all your rules in this inline array - "inline" : [] + "inline" : [] }, // The validator is an object that will validate rules and annotations and provide feedback on either authentication or authorization issues. - "validator" : "SecurityValidator@contentbox", + "validator": "SecurityValidator@contentbox", // Firewall database event logs. - "logs" : { - "enabled" : true, - "table" : "cbsecurity_logs", - "autoCreate" : true + "logs" : { + "enabled" : true, + "table" : "cbsecurity_logs", + "autoCreate": true } }, /** @@ -68,20 +68,20 @@ component { * -------------------------------------------------------------------------- * These settings configures the cbcsrf module. Look at the module configuration for more information */ - csrf : { + csrf: { // By default we load up an interceptor that verifies all non-GET incoming requests against the token validations - enableAutoVerifier : false, + enableAutoVerifier : false, // A list of events to exclude from csrf verification, regex allowed: e.g. stripe\..* - verifyExcludes : [], + verifyExcludes : [], // By default, all csrf tokens have a life-span of 30 minutes. After 30 minutes, they expire and we aut-generate new ones. // If you do not want expiring tokens, then set this value to 0 - rotationTimeout : 30, + rotationTimeout : 30, // Enable the /cbcsrf/generate endpoint to generate cbcsrf tokens for secured users. - enableEndpoint : false, + enableEndpoint : false, // The WireBox mapping to use for the CacheStorage - cacheStorage : "CacheStorage@cbstorages", + cacheStorage : "CacheStorage@cbstorages", // Enable/Disable the cbAuth login/logout listener in order to rotate keys - enableAuthTokenRotator : true + enableAuthTokenRotator: true }, /** * -------------------------------------------------------------------------- @@ -90,116 +90,115 @@ component { * This section is the way to configure cbsecurity for header detection, inspection and setting for common * security exploits like XSS, ClickJacking, Host Spoofing, IP Spoofing, Non SSL usage, HSTS and much more. */ - securityHeaders : { + securityHeaders: { // If you trust the upstream then we will check the upstream first for specific headers - "trustUpstream" : true, + "trustUpstream" : true, // Content Security Policy // Content Security Policy (CSP) is an added layer of security that helps to detect and mitigate certain types of attacks, // including Cross-Site Scripting (XSS) and data injection attacks. These attacks are used for everything from data theft, to // site defacement, to malware distribution. // https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP - "contentSecurityPolicy" : { + "contentSecurityPolicy": { // Disabled by defautl as it is totally customizable - "enabled" : false, + "enabled": false, // The custom policy to use, by default we don't include any - "policy" : "" + "policy" : "" }, // The X-Content-Type-Options response HTTP header is a marker used by the server to indicate that the MIME types advertised in // the Content-Type headers should be followed and not be changed => X-Content-Type-Options: nosniff // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Content-Type-Options - "contentTypeOptions" : { "enabled" : true }, - "customHeaders" : { - // Name : value pairs as you see fit. - }, + "contentTypeOptions": { "enabled": true }, + // Name : value pairs as you see fit. These are added to all responses and can be used for custom headers or to add headers that are not yet supported by cbsecurity + "customHeaders" : {}, // Disable Click jacking: X-Frame-Options: DENY OR SAMEORIGIN // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options - "frameOptions" : { "enabled" : true, "value" : "SAMEORIGIN" }, + "frameOptions" : { "enabled": true, "value": "SAMEORIGIN" }, // HTTP Strict Transport Security (HSTS) // The HTTP Strict-Transport-Security response header (often abbreviated as HSTS) // informs browsers that the site should only be accessed using HTTPS, and that any future attempts to access it // using HTTP should automatically be converted to HTTPS. // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Strict-Transport-Security, - "hsts" : { - "enabled" : false, + "hsts" : { + "enabled" : false, // The time, in seconds, that the browser should remember that a site is only to be accessed using HTTPS, 1 year is the default - "max-age" : "31536000", + "max-age" : "31536000", // See Preloading Strict Transport Security for details. Not part of the specification. - "preload" : false, + "preload" : false, // If this optional parameter is specified, this rule applies to all of the site's subdomains as well. - "includeSubDomains" : false + "includeSubDomains": false }, // Validates the host or x-forwarded-host to an allowed list of valid hosts - "hostHeaderValidation" : { - "enabled" : false, + "hostHeaderValidation": { + "enabled" : false, // Allowed hosts list - "allowedHosts" : "" + "allowedHosts": "" }, // Validates the ip address of the incoming request - "ipValidation" : { - "enabled" : false, + "ipValidation": { + "enabled" : false, // Allowed IP list - "allowedIPs" : "" + "allowedIPs": "" }, // The Referrer-Policy HTTP header controls how much referrer information (sent with the Referer header) should be included with requests. // Aside from the HTTP header, you can set this policy in HTML. // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Referrer-Policy - "referrerPolicy" : { "enabled" : true, "policy" : "same-origin" }, + "referrerPolicy" : { "enabled": true, "policy": "same-origin" }, // Detect if the incoming requests are NON-SSL and if enabled, redirect with SSL - "secureSSLRedirects" : { "enabled" : false }, + "secureSSLRedirects": { "enabled": false }, // Some browsers have built in support for filtering out reflected XSS attacks. Not foolproof, but it assists in XSS protection. // https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection, // X-XSS-Protection: 1; mode=block - "xssProtection" : { "enabled" : true, "mode" : "block" } + "xssProtection" : { "enabled": true, "mode": "block" } }, // JWT Settings - "jwt" : { + "jwt": { // The issuer authority for the tokens, placed in the `iss` claim - "issuer" : "contentbox", + "issuer" : "contentbox", // The jwt secret encoding key to use - "secretKey" : getSystemSetting( "JWT_SECRET", "" ), + "secretKey" : getSystemSetting( "JWT_SECRET", "" ), // by default it uses the authorization bearer header, but you can also pass a custom one as well or as an rc variable. - "customAuthHeader" : "x-auth-token", + "customAuthHeader" : "x-auth-token", // The expiration in minutes for the jwt tokens - "expiration" : 60, + "expiration" : 60, // If true, enables refresh tokens, longer lived tokens (not implemented yet) - "enableRefreshTokens" : true, + "enableRefreshTokens" : true, // The default expiration for refresh tokens, defaults to 7 days - "refreshExpiration" : 10080, + "refreshExpiration" : 10080, // The custom header to inspect for refresh tokens - "customRefreshHeader" : "x-refresh-token", + "customRefreshHeader" : "x-refresh-token", // If enabled, the JWT validator will inspect the request for refresh tokens and expired access tokens // It will then automatically refresh them for you and return them back as // response headers in the same request according to the `customRefreshHeader` and `customAuthHeader` - "enableAutoRefreshValidator" : true, + "enableAutoRefreshValidator": true, // Enable the POST > /cbsecurity/refreshtoken API endpoint - "enableRefreshEndpoint" : false, + "enableRefreshEndpoint" : false, // encryption algorithm to use, valid algorithms are: HS256, HS384, and HS512 - "algorithm" : "HS512", + "algorithm" : "HS512", // Which claims neds to be present on the jwt token or `TokenInvalidException` upon verification and decoding - "requiredClaims" : [], + "requiredClaims" : [], // The token storage settings - "tokenStorage" : { + "tokenStorage" : { // enable or not, default is true - "enabled" : true, + "enabled" : true, // A cache key prefix to use when storing the tokens - "keyPrefix" : "cbjwt_", + "keyPrefix" : "cbjwt_", // The driver to use: db, cachebox or a WireBox ID - "driver" : "db", + "driver" : "db", // Driver specific properties - "properties" : { - "table" : "cb_jwt", - "autoCreate" : true, - "rotationDays" : 7, - "rotationFrequency" : 60 + "properties": { + "table" : "cb_jwt", + "autoCreate" : true, + "rotationDays" : 7, + "rotationFrequency": 60 } } }, - visualizer : { - "enabled" : true, - "secured" : true, - "securityRule" : { "permissions" : "SYSTEM_AUTH_LOGS" } + visualizer: { + "enabled" : true, + "secured" : true, + "securityRule": { "permissions": "SYSTEM_AUTH_LOGS" } } }; } -} +} \ No newline at end of file diff --git a/config/modules/cbstorages.cfc b/config/modules/cbstorages.cfc index 526d48e290..d9616545de 100644 --- a/config/modules/cbstorages.cfc +++ b/config/modules/cbstorages.cfc @@ -1,6 +1,6 @@ component { - function configure(){ + function configure() { /** * -------------------------------------------------------------------------- * ColdBox Storages @@ -9,38 +9,38 @@ component { */ return { // Cache Storage Settings - cacheStorage : { + cacheStorage: { // The CacheBox registered cache to store data in - cachename : "sessions", + cachename : "sessions", // The default timeout of the session bucket, defaults to 60 minutes - timeout : getSystemSetting( "COLDBOX_SESSION_TIMEOUT", 60 ), + timeout : getSystemSetting( "COLDBOX_SESSION_TIMEOUT", 60 ), // The identifierProvider is a closure/udf that will return a unique identifier according to your rules // If you do not provide one, then we will search in session, cookie and url for the ColdFusion identifier. // identifierProvider : function(){} - identifierProvider : "" // If it's a simple value, we ignore it. + identifierProvider: "" // If it's a simple value, we ignore it. }, // Cookie Storage settings - cookieStorage : { + cookieStorage: { // If browser does not support Secure Sockets Layer (SSL) security, the cookie is not sent. // To use the cookie, the page must be accessed using the https protocol. - secure : false, + secure : false, // If yes, sets cookie as httponly so that it cannot be accessed using JavaScripts - httpOnly : true, + httpOnly : true, // Domain in which cookie is valid and to which cookie content can be sent from the user's system. By default, the cookie // is only available to the server that set it. Use this attribute to make the cookie available to other servers - domain : "", + domain : "", // Use encryption of values - useEncryption : false, + useEncryption : false, // The encryption key to use for the encryption - encryptionKey : generateSecretKey( "AES", "128" ), + encryptionKey : generateSecretKey( "AES", "128" ), // The unique seeding key to use: keep it secret, keep it safe - encryptionSeed : "cbstorages", + encryptionSeed : "cbstorages", // The algorithm to use: https://cfdocs.org/encrypt - encryptionAlgorithm : "AES", + encryptionAlgorithm: "AES", // The encryption encoding to use - encryptionEncoding : "Base64" + encryptionEncoding : "Base64" } }; } -} +} \ No newline at end of file diff --git a/config/modules/cbswagger.cfc b/config/modules/cbswagger.cfc index 5e9e5faef5..844282d7df 100644 --- a/config/modules/cbswagger.cfc +++ b/config/modules/cbswagger.cfc @@ -1,6 +1,6 @@ component { - function configure(){ + function configure() { /** * -------------------------------------------------------------------------- * CBSwagger Configuration @@ -9,125 +9,121 @@ component { */ return { // The route prefix to search. Routes beginning with this prefix will be determined to be api routes - "routes" : [ "cbapi" ], + "routes" : [ "cbapi"], // Routes to exclude from the generated spec - "excludeRoutes" : [ "cbapi/v1/:anything/" ], + "excludeRoutes": [ "cbapi/v1/:anything/"], // The default output format, either json or yml - "defaultFormat" : "json", + "defaultFormat": "json", // A convention route, relative to your app root, where request/response samples are stored ( e.g. resources/apidocs/responses/[module].[handler].[action].[HTTP Status Code].json ) - "samplesPath" : "resources/apidocs", + "samplesPath" : "resources/apidocs", // Information about your API // https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#infoObject - "info" : { + "info" : { // REQUIRED A title for your API - "title" : "ContentBox CMS API", + "title" : "ContentBox CMS API", // A short description of the application. CommonMark syntax MAY be used for rich text representation. - "description" : "The ContentBox Headless CMS API", + "description" : "The ContentBox Headless CMS API", // A URL to the Terms of Service for the API. MUST be in the format of a URL. - "termsOfService" : "", + "termsOfService": "", // Contact information for the exposed API. - "contact" : { + "contact" : { // The identifying name of the contact person/organization. - "name" : "Ortus Solutions", + "name" : "Ortus Solutions", // The URL pointing to the contact information. MUST be in the format of a URL. - "url" : "https://www.ortussolutions.com", + "url" : "https://www.ortussolutions.com", // The email address of the contact person/organization. MUST be in the format of an email address. - "email" : "info@ortussolutions.com" + "email": "info@ortussolutions.com" }, // License information for the exposed API. - "license" : { + "license": { // The license name used for the API. - "name" : "Apache2", + "name": "Apache2", // A URL to the license used for the API. MUST be in the format of a URL. - "url" : "https://www.apache.org/licenses/LICENSE-2.0.html" + "url" : "https://www.apache.org/licenses/LICENSE-2.0.html" }, // REQUIRED. The version of the OpenAPI document (which is distinct from the OpenAPI Specification version or the API implementation version). - "version" : "@version.number@" + "version": "@version.number@" }, // An array of Server Objects, which provide connectivity information to a target server. If the servers property is not provided, or is an empty array, the default value would be a Server Object with a url value of /. // https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#serverObject - "servers" : [ + "servers": [ { - "url" : "http://127.0.0.1:8589", - "description" : "Development Server" + "url" : "http://127.0.0.1:8589", + "description": "Development Server" } ], // An element to hold various schemas for the specification. // https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#componentsObject - "components" : { + "components": { // Define your security schemes here // https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#securitySchemeObject - "securitySchemes" : { - "ApiKeyAuth" : { - "type" : "apiKey", - "description" : "User your JWT as an Api Key for security", - "name" : "x-auth-token", - "in" : "header" + "securitySchemes": { + "ApiKeyAuth": { + "type" : "apiKey", + "description": "User your JWT as an Api Key for security", + "name" : "x-auth-token", + "in" : "header" }, - "ApiKeyQueryAuth" : { - "type" : "apiKey", - "description" : "User your JWT as an Api Key for security", - "name" : "x-auth-token", - "in" : "query" + "ApiKeyQueryAuth": { + "type" : "apiKey", + "description": "User your JWT as an Api Key for security", + "name" : "x-auth-token", + "in" : "query" }, - "BearerAuth" : { - "type" : "http", - "description" : "User your JWT in the bearer Authorization header", - "scheme" : "bearer", - "bearerFormat" : "JWT" + "BearerAuth": { + "type" : "http", + "description" : "User your JWT in the bearer Authorization header", + "scheme" : "bearer", + "bearerFormat": "JWT" } } }, // A declaration of which security mechanisms can be used across the API. // https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#securityRequirementObject - "security" : [ - { "ApiKeyAuth" : [] }, - { "ApiKeyQueryAuth" : [] }, - { "BearerAuth" : [] } - ], + "security": [ { "ApiKeyAuth": [] }, { "ApiKeyQueryAuth": [] }, { "BearerAuth": [] }], // A list of tags used by the specification with additional metadata. // https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#tagObject - "tags" : [ - { "name" : "Authors", "description" : "Author operations" }, + "tags" : [ + { "name": "Authors", "description": "Author operations" }, { - "name" : "Authentication", - "description" : "Authentication operations" + "name" : "Authentication", + "description": "Authentication operations" }, { - "name" : "Categories", - "description" : "Category operations" + "name" : "Categories", + "description": "Category operations" }, { - "name" : "Comments", - "description" : "Comment operations" + "name" : "Comments", + "description": "Comment operations" }, { - "name" : "ContentStore", - "description" : "Content store operations" + "name" : "ContentStore", + "description": "Content store operations" }, { - "name" : "Entries", - "description" : "Blog entry operations" + "name" : "Entries", + "description": "Blog entry operations" }, - { "name" : "Menus", "description" : "Menu operations" }, - { "name" : "Pages", "description" : "Pages operations" }, - { "name" : "Sites", "description" : "Site operations" }, + { "name": "Menus", "description": "Menu operations" }, + { "name": "Pages", "description": "Pages operations" }, + { "name": "Sites", "description": "Site operations" }, { - "name" : "Settings", - "description" : "Global setting operations" + "name" : "Settings", + "description": "Global setting operations" }, { - "name" : "Versions", - "description" : "Content versions operations" + "name" : "Versions", + "description": "Content versions operations" } ], // Additional external documentation. // https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#externalDocumentationObject - "externalDocs" : { - "description" : "Find more info here", - "url" : "https://contentbox.ortusbooks.com" + "externalDocs": { + "description": "Find more info here", + "url" : "https://contentbox.ortusbooks.com" } }; } -} +} \ No newline at end of file diff --git a/config/modules/contentbox.cfc b/config/modules/contentbox.cfc index 0fed9eac24..dc02f718e9 100644 --- a/config/modules/contentbox.cfc +++ b/config/modules/contentbox.cfc @@ -1,6 +1,6 @@ component { - function configure(){ + function configure() { /** * -------------------------------------------------------------------------- * ContentBox Runtime Config @@ -8,17 +8,15 @@ component { */ return { // Array of mixins (eg: /includes/contentHelpers.cfm) to inject into all content objects - "contentHelpers" : [], + "contentHelpers": [], // Setting Overrides - "settings" : { + "settings" : { // Global settings - "global" : {}, + "global": {}, // Site specific settings according to site slug - "sites" : { - // siteSlug : { ... } - } + "sites" : {} } }; } -} +} \ No newline at end of file diff --git a/config/modules/mementifier.cfc b/config/modules/mementifier.cfc index bc71dc717a..047bf75a77 100644 --- a/config/modules/mementifier.cfc +++ b/config/modules/mementifier.cfc @@ -1,6 +1,6 @@ component { - function configure(){ + function configure() { /** * -------------------------------------------------------------------------- * Mementifier Settings @@ -9,22 +9,22 @@ component { */ return { // Turn on to use the ISO8601 date/time formatting on all processed date/time properites, else use the masks - iso8601Format : true, + iso8601Format : true, // The default date mask to use for date properties - dateMask : "yyyy-MM-dd", + dateMask : "yyyy-MM-dd", // The default time mask to use for date properties - timeMask : "HH:mm: ss", + timeMask : "HH:mm: ss", // Enable orm auto default includes: If true and an object doesn't have any `memento` struct defined // this module will create it with all properties and relationships it can find for the target entity // leveraging the cborm module. - ormAutoIncludes : true, + ormAutoIncludes : true, // The default value for relationships/getters which return null - nullDefaultValue : "", + nullDefaultValue : "", // Don't check for getters before invoking them - trustedGetters : false, + trustedGetters : false, // If not empty, convert all date/times to the specific timezone - convertToTimezone : "UTC" + convertToTimezone: "UTC" }; } -} +} \ No newline at end of file diff --git a/handlers/Main.cfc b/handlers/Main.cfc index 8ac50581f8..258a2e41b8 100755 --- a/handlers/Main.cfc +++ b/handlers/Main.cfc @@ -1 +1,45 @@ -component{ // Default Action function index(event,rc,prc){ prc.welcomeMessage = "Welcome to ContentBox Modular CMS!"; event.setView( "main/index" ); } /************************************** IMPLICIT ACTIONS *********************************************/ function onAppInit(event,rc,prc){ } function onRequestStart(event,rc,prc){ } function onRequestEnd(event,rc,prc){ } function onSessionStart(event,rc,prc){ } function onSessionEnd(event,rc,prc){ var sessionScope = event.getValue("sessionReference"); var applicationScope = event.getValue("applicationReference"); } function onException(event,rc,prc){ //Grab Exception From request collection, placed by ColdBox var exceptionBean = event.getValue("ExceptionBean"); //Place exception handler below: } function onMissingTemplate(event,rc,prc){ //Grab missingTemplate From request collection, placed by ColdBox var missingTemplate = event.getValue("missingTemplate"); } } \ No newline at end of file +component { + + // Default Action + function index( event, rc, prc ) { + prc.welcomeMessage = "Welcome to ContentBox Modular CMS!"; + event.setView( "main/index" ); + } + + /************************************** IMPLICIT ACTIONS *********************************************/ + + function onAppInit( event, rc, prc ) { + + } + + function onRequestStart( event, rc, prc ) { + + } + + function onRequestEnd( event, rc, prc ) { + + } + + function onSessionStart( event, rc, prc ) { + + } + + function onSessionEnd( event, rc, prc ) { + var sessionScope = event.getValue( "sessionReference" ); + var applicationScope = event.getValue( "applicationReference" ); + } + + function onException( event, rc, prc ) { + // Grab Exception From request collection, placed by ColdBox + var exceptionBean = event.getValue( "ExceptionBean" ); + + + // Place exception handler below: + } + + function onMissingTemplate( event, rc, prc ) { + // Grab missingTemplate From request collection, placed by ColdBox + var missingTemplate = event.getValue( "missingTemplate" ); + } + +} \ No newline at end of file diff --git a/layouts/Main.cfm b/layouts/Main.cfm index daf62c53c5..25da1b7700 100644 --- a/layouts/Main.cfm +++ b/layouts/Main.cfm @@ -1 +1,16 @@ - #html.doctype()# Welcome to ContentBox! #renderView()# \ No newline at end of file + +#html.doctype()# + + + + Welcome to ContentBox! + + + + + + + #renderView()# + + + diff --git a/lib/.gitkeep b/lib/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/modules/contentbox/Application.cfc b/modules/contentbox/Application.cfc index 21e64113d3..bb2ba391db 100644 --- a/modules/contentbox/Application.cfc +++ b/modules/contentbox/Application.cfc @@ -1,5 +1,4 @@ component { - abort; -} +} \ No newline at end of file diff --git a/modules/contentbox/ModuleConfig.cfc b/modules/contentbox/ModuleConfig.cfc index 4bda2cb294..2c169390d9 100755 --- a/modules/contentbox/ModuleConfig.cfc +++ b/modules/contentbox/ModuleConfig.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -6,142 +6,140 @@ * ContentBox Core module configuration */ component { - // Module Properties - this.title = "ContentBox Core"; - this.author = "Ortus Solutions, Corp"; - this.webURL = "https://www.ortussolutions.com"; - this.version = "@version.number@+@build.number@"; - this.description = "This is the core module used to power the admin, RESTful and UI modules"; - this.viewParentLookup = true; + this.title = "ContentBox Core"; + this.author = "Ortus Solutions, Corp"; + this.webURL = "https://www.ortussolutions.com"; + this.version = "@version.number@+@build.number@"; + this.description = "This is the core module used to power the admin, RESTful and UI modules"; + this.viewParentLookup = true; this.layoutParentLookup = true; - this.entryPoint = "cbcore"; - this.modelNamespace = "contentbox"; - this.cfmapping = "contentbox"; + this.entryPoint = "cbcore"; + this.modelNamespace = "contentbox"; + this.cfmapping = "contentbox"; // Load ContentBox Dependencies First. - this.dependencies = [ "contentbox-deps" ]; + this.dependencies = [ "contentbox-deps"]; /** * Configure Module */ - function configure(){ + function configure() { // Verify custom module, this is needed for registration and loading. verifyCustomModule(); // contentbox settings - settings = { + variables.settings = { // Code name - "codename" : "Psalm 144:1", - "codenameLink" : "https://www.bible.com/bible/114/psa.144.1.nkjv", + "codename" : "Psalm 144:1", + "codenameLink": "https://www.bible.com/bible/114/psa.144.1.nkjv", // Officially supported languages for modules - "languages" : [ "de_DE", "en_US", "es_SV", "it_IT", "pt_BR" ], + "languages" : [ "de_DE", "en_US", "es_SV", "it_IT", "pt_BR"], // cbSecurity settings - "cbSecurity" : { + "cbSecurity" : { // Load the security rules for ContentBox from our db model - "firewall" : { - "rules" : { - "provider" : { - "source" : "model", - "properties" : { - "model" : "securityRuleService@contentbox", - "method" : "getSecurityRules" + "firewall": { + "rules": { + "provider": { + "source" : "model", + "properties": { + "model" : "securityRuleService@contentbox", + "method": "getSecurityRules" } } } } }, // Array of mixins to inject into all content objects - "contentHelpers" : [], + "contentHelpers": [], // Setting Overrides - "settings" : { + "settings" : { // Global settings - "global" : {}, + "global": {}, // Site specific settings according to site slug - "sites" : { - // siteSlug : { ... } - } + "sites" : {} } }; // i18n - cbi18n = { resourceBundles : { "cbcore" : "#moduleMapping#/i18n/cbcore" } }; + variables.cbi18n = { resourceBundles: { "cbcore": "#moduleMapping#/i18n/cbcore" } }; // CB Module Conventions - conventions = { layoutsLocation : "themes", viewsLocation : "themes" }; + variables.conventions = { layoutsLocation: "themes", viewsLocation: "themes" }; // Parent Affected Settings - parentSettings = { + variables.parentSettings = { // File Browser module name override - filebrowser_module_name : "contentbox-filebrowser" + filebrowser_module_name: "contentbox-filebrowser" }; // ContentBox Core Custom Events - interceptorSettings = { - customInterceptionPoints : [ - "cb_onContentRendering", - "cb_onContentStoreRendering" - ] + variables.interceptorSettings = { + customInterceptionPoints: [ "cb_onContentRendering", "cb_onContentStoreRendering"] }; // Async Executors for ContentBox Core // executors = { "contentbox-tasks" : { type : "scheduled", threads : 20 } }; // interceptors - interceptors = [ + variables.interceptors = [ // Rate Limiter { - class : "contentbox.models.security.RateLimiter", - name : "RateLimiter@contentbox" + class: "contentbox.models.security.RateLimiter", + name : "RateLimiter@contentbox" }, // CB RSS Cache Cleanup Ghost { - class : "contentbox.models.rss.RSSCacheCleanup", - name : "RSSCacheCleanup@contentbox" + class: "contentbox.models.rss.RSSCacheCleanup", + name : "RSSCacheCleanup@contentbox" }, // CB Content Cache Cleanup Ghost { - class : "contentbox.models.content.util.ContentCacheCleanup", - name : "ContentCacheCleanup@contentbox" + class: "contentbox.models.content.util.ContentCacheCleanup", + name : "ContentCacheCleanup@contentbox" }, // Content Subscriptions { - class : "contentbox.models.subscriptions.SubscriptionListener", - name : "SubscriptionListener@contentbox" + class: "contentbox.models.subscriptions.SubscriptionListener", + name : "SubscriptionListener@contentbox" }, // Content Renderers, remember order is important. { - class : "contentbox.models.content.renderers.LinkRenderer", - name : "LinkRenderer@contentbox" + class: "contentbox.models.content.renderers.LinkRenderer", + name : "LinkRenderer@contentbox" }, { - class : "contentbox.models.content.renderers.WidgetRenderer", - name : "WidgetRenderer@contentbox" + class: "contentbox.models.content.renderers.WidgetRenderer", + name : "WidgetRenderer@contentbox" }, { - class : "contentbox.models.content.renderers.SettingRenderer", - name : "SettingRenderer@contentbox" + class: "contentbox.models.content.renderers.SettingRenderer", + name : "SettingRenderer@contentbox" }, { - class : "contentbox.models.content.renderers.MarkdownRenderer", - name : "MarkdownRenderer@contentbox" + class: "contentbox.models.content.renderers.MarkdownRenderer", + name : "MarkdownRenderer@contentbox" } ]; // Manual Mappings // binder.map( "customFieldService@contentbox" ).toDSL( "entityService:cbCustomField" ); - binder.map( "SystemUtil@contentbox" ).to( "coldbox.system.core.util.Util" ); + variables + .binder + .map( "SystemUtil@contentbox" ) + .to( "coldbox.system.core.util.Util" ); } /** * Development tier */ - function development(){ + function development() { + } /** * Fired when the module is registered and activated. */ - function onLoad(){ + function onLoad() { // Create `cb` alias : REMOVE BY CONTENTBOX NEXT MAJOR VERSION binder.mapDirectory( packagePath = "contentbox.models", namespace = "@cb" ); var settingService = wirebox.getInstance( "settingService@contentbox" ); @@ -156,20 +154,19 @@ component { if ( !diskService.has( "contentbox" ) ) { diskService.register( - "contentbox", - "Local", - { - path : expandPath( settingService.getSetting( "cb_media_directoryRoot" ) ), - diskUrl : function(){ - return variables.wirebox - .getInstance( "CBHelper@contentBox" ) - .site() - .getSiteRoot() - & - "/modules_app/contentbox-custom/_content" + "contentbox", + "Local", + { + path : expandPath( settingService.getSetting( "cb_media_directoryRoot" ) ), + diskUrl: function() { + return variables + .wirebox + .getInstance( "CBHelper@contentBox" ) + .site() + .getSiteRoot() & "/modules_app/contentbox-custom/_content"; + } } - } - ); + ); } // Startup the ContentBox modules, if any @@ -179,7 +176,8 @@ component { /** * Fired when the module is unregistered and unloaded */ - function onUnload(){ + function onUnload() { + } /************************************** APP LISTENERS *********************************************/ @@ -188,20 +186,19 @@ component { * Listen to when application and all modules are fully loaded. * We use this interception to startup some services and discoveries. */ - function afterConfigurationLoad( event, data, rc, prc ){ + function afterConfigurationLoad( event, data, rc, prc ) { // Discover all widgets wirebox.getInstance( "widgetservice@contentbox" ).getWidgets(); } - /************************************** PRIVATE *********************************************/ /** * Verify the custom module exists. If not, we will auto-generate one to avoid conflicts * and issues with new custom approaches. */ - private function verifyCustomModule(){ - var appPath = controller.getSetting( "ApplicationPath" ); + private function verifyCustomModule() { + var appPath = controller.getSetting( "ApplicationPath" ); var customModulesPath = appPath & "modules_app/contentbox-custom"; // Verify modules_app: just in case @@ -223,4 +220,4 @@ component { } } -} +} \ No newline at end of file diff --git a/modules/contentbox/config/Scheduler.cfc b/modules/contentbox/config/Scheduler.cfc index edb2c171db..faa9492cfc 100644 --- a/modules/contentbox/config/Scheduler.cfc +++ b/modules/contentbox/config/Scheduler.cfc @@ -3,7 +3,7 @@ component { /** * Configure the ColdBox Scheduler */ - function configure(){ + function configure() { /** * -------------------------------------------------------------------------- * Configuration Methods @@ -13,8 +13,6 @@ component { * - setExecutor( executorObject ) : change the executor if needed */ - - /** * -------------------------------------------------------------------------- * Register Scheduled Tasks @@ -25,58 +23,61 @@ component { // Rotates the login audit logs task( "login-tracker-rotation" ) - .call( () => { - getInstance( "LoginTrackerService@contentbox" ).rotate(); - } ) + .call( + () => { + getInstance( "LoginTrackerService@contentbox" ).rotate(); + } + ) .everyHour() .delay( 1, "hours" ) .onOneServer(); - ; // Deletes all moderated comments that have expired in the inbox task( "comment-expirations" ) - .call( () => { - getInstance( "siteService@contentbox" ) - .getAll() - .each( function( thisSite ){ - var commentExpirationDays = getInstance( "settingService@contentbox" ).getSiteSetting( - arguments.thisSite.getSlug(), - "cb_comments_moderation_expiration" + .call( + () => { + getInstance( "siteService@contentbox" ).getAll().each( + function( thisSite ) { + var commentExpirationDays = getInstance( "settingService@contentbox" ).getSiteSetting( arguments.thisSite.getSlug(), + "cb_comments_moderation_expiration" ); + + if ( commentExpirationDays > 0 ) { + log.info( + "Starting to expire comments on site: #arguments.thisSite.getSlug()#..." + ); + + getInstance( "commentService@contentbox" ).deleteUnApproved( expirationDays = commentExpirationDays ); + + log.info( + "Moderated comments expired for site (#arguments.thisSite.getSlug()#) using (#commentExpirationDays#) days for expiration!" + ); + } else { + log.info( + "Comment expiration not enabled for site (#arguments.thisSite.getSlug()#), skipping." + ); + } + } ); - - if ( commentExpirationDays > 0 ) { - log.info( "Starting to expire comments on site: #arguments.thisSite.getSlug()#..." ); - - // now we have the green light to find and kill any old, moderated comments - getInstance( "commentService@contentbox" ).deleteUnApproved( - expirationDays = commentExpirationDays - ); - - log.info( - "Moderated comments expired for site (#arguments.thisSite.getSlug()#) using (#commentExpirationDays#) days for expiration!" - ); - } else { - log.info( - "Comment expiration not enabled for site (#arguments.thisSite.getSlug()#), skipping." - ); - } - } ); - } ) + } + ) .everyHour() .delay( 1, "hours" ) + // now we have the green light to find and kill any old, moderated comments + .onOneServer(); } /** * Called before the scheduler is going to be shutdown */ - function onShutdown(){ + function onShutdown() { + } /** * Called after the scheduler has registered all schedules */ - function onStartup(){ + function onStartup() { log.info( "√ ContentBox Core Scheduler started successfully!" ); } @@ -86,11 +87,11 @@ component { * @task The task that got executed * @exception The ColdFusion exception object */ - function onAnyTaskError( required task, required exception ){ + function onAnyTaskError( required task, required exception ) { log.error( - "The task (#arguments.task.getname()#) failed to executed. Caused by: #exception.message & exception.detail#", - exception.stacktrace - ); + "The task (#arguments.task.getname()#) failed to executed. Caused by: #exception.message & exception.detail#", + exception.stacktrace + ); } /** @@ -99,11 +100,11 @@ component { * @task The task that got executed * @result The result (if any) that the task produced */ - function onAnyTaskSuccess( required task, result ){ + function onAnyTaskSuccess( required task, result ) { log.info( - "Task (#arguments.task.getName()#) completed succesfully in #arguments.task.getStats().lastExecutionTime# ms", - arguments.task.getStats() - ); + "Task (#arguments.task.getName()#) completed succesfully in #arguments.task.getStats().lastExecutionTime# ms", + arguments.task.getStats() + ); } /** @@ -111,8 +112,10 @@ component { * * @task The task about to be executed */ - function beforeAnyTask( required task ){ - log.info( "Starting to execute task (#arguments.task.getName()#)..." ); + function beforeAnyTask( required task ) { + log.info( + "Starting to execute task (#arguments.task.getName()#)..." + ); } /** @@ -121,7 +124,8 @@ component { * @task The task that got executed * @result The result (if any) that the task produced */ - function afterAnyTask( required task, result ){ + function afterAnyTask( required task, result ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/2020_01_01_150933_init.cfc b/modules/contentbox/migrations/2020_01_01_150933_init.cfc index b0dbd863c0..44cbff231c 100755 --- a/modules/contentbox/migrations/2020_01_01_150933_init.cfc +++ b/modules/contentbox/migrations/2020_01_01_150933_init.cfc @@ -2,80 +2,88 @@ * This migration is to migrate ContentBox v4 databases to v5 standards. */ component { - // DI property name="migrationService" inject="MigrationService@cfmigrations"; - // Include Utils - include template = "./util/MigrationUtils.cfm"; + include template="./util/MigrationUtils.cfm"; - function up( schema, query ){ + function up( schema, query ) { // In order of dependency var migrations = [ - "sites" : { table : "cb_site" }, - "settings" : { table : "cb_setting" }, - "permissions" : { table : "cb_permission" }, - "permission_groups" : { table : "cb_permissionGroup" }, - "group_permissions" : { table : "cb_groupPermissions" }, - "roles" : { table : "cb_role" }, - "role_permissions" : { table : "cb_rolePermissions" }, - "author" : { table : "cb_author" }, - "author_permissions" : { table : "cb_authorPermissions" }, - "author_permission_groups": { table : "cb_authorPermissionGroups" }, - "category" : { table : "cb_category" }, - "content" : { table : "cb_content" }, - "content_versions" : { table : "cb_contentVersion" }, - "content_categories" : { table : "cb_contentCategories" }, - "contentStore" : { table : "cb_contentStore" }, - "entry" : { table : "cb_entry" }, - "page" : { table : "cb_page" }, - "stats" : { table : "cb_stats" }, - "related_content" : { table : "cb_relatedContent" }, - "content_templates" : { table : "cb_contentTemplate" }, - "comments" : { table : "cb_comment" }, - "custom_fields" : { table : "cb_customfield" }, - "login_attempts" : { table : "cb_loginAttempts" }, - "menus" : { table : "cb_menu" }, - "menu_items" : { table : "cb_menuItem" }, - "modules" : { table : "cb_module" }, - "relocations" : { table : "cb_relocations" }, - "security_rules" : { table : "cb_securityRule" }, - "subscribers" : { table : "cb_subscribers" }, - "subscriptions" : { table : "cb_subscriptions" }, - "comment_subscriptions" : { table : "cb_commentSubscriptions" }, - "security_logs" : { table : "cbsecurity_logs" }, - "jwt" : { table : "cb_jwt" } + "sites" : { table: "cb_site" }, + "settings" : { table: "cb_setting" }, + "permissions" : { table: "cb_permission" }, + "permission_groups" : { table: "cb_permissionGroup" }, + "group_permissions" : { table: "cb_groupPermissions" }, + "roles" : { table: "cb_role" }, + "role_permissions" : { table: "cb_rolePermissions" }, + "author" : { table: "cb_author" }, + "author_permissions" : { table: "cb_authorPermissions" }, + "author_permission_groups": { table: "cb_authorPermissionGroups" }, + "category" : { table: "cb_category" }, + "content" : { table: "cb_content" }, + "content_versions" : { table: "cb_contentVersion" }, + "content_categories" : { table: "cb_contentCategories" }, + "contentStore" : { table: "cb_contentStore" }, + "entry" : { table: "cb_entry" }, + "page" : { table: "cb_page" }, + "stats" : { table: "cb_stats" }, + "related_content" : { table: "cb_relatedContent" }, + "content_templates" : { table: "cb_contentTemplate" }, + "comments" : { table: "cb_comment" }, + "custom_fields" : { table: "cb_customfield" }, + "login_attempts" : { table: "cb_loginAttempts" }, + "menus" : { table: "cb_menu" }, + "menu_items" : { table: "cb_menuItem" }, + "modules" : { table: "cb_module" }, + "relocations" : { table: "cb_relocations" }, + "security_rules" : { table: "cb_securityRule" }, + "subscribers" : { table: "cb_subscribers" }, + "subscriptions" : { table: "cb_subscriptions" }, + "comment_subscriptions" : { table: "cb_commentSubscriptions" }, + "security_logs" : { table: "cbsecurity_logs" }, + "jwt" : { table: "cb_jwt" } ]; - systemOutput( "Starting to initialize the ContentBox Database, this will take a while...", true ); + systemOutput( + "Starting to initialize the ContentBox Database, this will take a while...", + true + ); - migrations.each( ( migration, record ) => { - systemOutput( "Migrating [#migration#]...", true ); + migrations.each( + ( migration, record ) => { + systemOutput( "Migrating [#migration#]...", true ); - if ( !schema.hasTable( record.table ) ) { - systemOutput( "- Table doesn't exist (#record.table#) creating it...", true ); - new "init.create_#migration#"( ).up( schema, query ); + if ( !schema.hasTable( record.table ) ) { + systemOutput( + "- Table doesn't exist (#record.table#) creating it...", + true + ); + new "init.create_#migration#"().up( schema, query ); - // Seeding Permissions - if ( migration == "permissions" ) { - systemOutput( "- Seeding permissions...", true ); - new init.seed_permissions().seed( schema, query ); - } + if ( migration == "permissions" ) { + systemOutput( "- Seeding permissions...", true ); + new init.seed_permissions().seed( schema, query ); + } - // Seeding Roles - if ( migration == "role_permissions" ) { - systemOutput( "- Seeding roles...", true ); - new init.seed_roles().seed( schema, query ); + if ( migration == "role_permissions" ) { + systemOutput( "- Seeding roles...", true ); + new init.seed_roles().seed( schema, query ); + } + } else { + systemOutput( + "√ Table (#record.table#) already exists, skipping...", + true + ); + } } - } else { - systemOutput( "√ Table (#record.table#) already exists, skipping...", true ); - } - } ); + ); systemOutput( "√ Database structure complete", true ); } - function down( schema, query ){ + function down( schema, query ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/2020_08_24_150933_v5Upgrade.cfc b/modules/contentbox/migrations/2020_08_24_150933_v5Upgrade.cfc index 4346c7849f..03e6b0a28e 100755 --- a/modules/contentbox/migrations/2020_08_24_150933_v5Upgrade.cfc +++ b/modules/contentbox/migrations/2020_08_24_150933_v5Upgrade.cfc @@ -2,41 +2,21 @@ * This migration is to migrate ContentBox v4 databases to v5 standards. */ component { - // DI property name="migrationService" inject="MigrationService@cfmigrations"; - // Include Utils include template="./util/MigrationUtils.cfm"; - variables.today = now(); - variables.siteTables = [ - "cb_category", - "cb_content", - "cb_menu", - "cb_setting" - ]; + variables.today = now(); + variables.siteTables = [ "cb_category", "cb_content", "cb_menu", "cb_setting"]; variables.newPermissions = [ { - name : "SITES_ADMIN", - description : "Ability to manage sites" + name : "SITES_ADMIN", + description: "Ability to manage sites" } ]; - private function isContentBox4(){ - try { - return !hasColumn( "cb_setting", "FK_siteID" ); - } catch ( any e ) { - // check if we don't have a database yet. - if ( findNoCase( "there is no table", e.message ) ) { - return false; - } else { - rethrow; - } - } - } - - function up( schema, query ){ + function up( schema, query ) { // If you are on version 4 continue, else skip // If cb_setting doesn't have a FK_siteID then it's 4 if ( !isContentBox4() ) { @@ -49,13 +29,13 @@ component { // Get the db schema name, we might need it when dropping keys variables.dbSchema = migrationService.getSchema(); - variables.uuidLib = createObject( "java", "java.util.UUID" ); + variables.uuidLib = createObject( "java", "java.util.UUID" ); scopeGrammarUDFs( argumentCollection = arguments ); try { migrateIdentifiersToGUIDs( argumentCollection = arguments ); - } catch ( any e ) { + } catch (any e) { systemOutput( e.message, true ); systemOutput( e.stacktrace, true ); transactionRollback(); @@ -79,24 +59,31 @@ component { // Update Slugs/Titles to 1000 characters dropIndexesForTableColumn( "cb_content", "title" ); dropIndexesForTableColumn( "cb_content", "slug" ); - schema.alter( "cb_content", function( table ){ - table.modifyColumn( "title", table.string( "title", 500 ) ); - table.modifyColumn( "slug", table.string( "slug", 500 ) ); - table.modifyColumn( "featuredImage", table.string( "featuredImage", 500 ).nullable() ); - table.modifyColumn( "featuredImageURL", table.string( "featuredImageURL", 500 ).nullable() ); - // Rebuild Indexes - table.index( [ "slug" ], "idx_slug" ); - table.index( [ "slug", "isPublished" ], "idx_publishedSlug" ); - table.index( [ "title", "isPublished" ], "idx_search" ); - } ); + schema.alter( + "cb_content", + function( table ) { + table.modifyColumn( "title", table.string( "title", 500 ) ); + table.modifyColumn( "slug", table.string( "slug", 500 ) ); + table.modifyColumn( "featuredImage", table.string( "featuredImage", 500 ).nullable() ); + table.modifyColumn( "featuredImageURL", + table.string( "featuredImageURL", 500 ).nullable() ); + + table.index( [ "slug"], "idx_slug" ); + table.index( [ "slug", "isPublished"], "idx_publishedSlug" ); + table.index( [ "title", "isPublished"], "idx_search" ); + } + ); // Create Category isPublic with indexes if ( !hasColumn( "cb_category", "isPublic" ) ) { - schema.alter( "cb_category", ( table ) => { - table.addColumn( table.boolean( "isPublic" ).default( true ) ); - table.index( [ "isPublic" ], "idx_isPublic" ); - } ); + schema.alter( + "cb_category", + ( table ) => { + table.addColumn( table.boolean( "isPublic" ).default( true ) ); + table.index( [ "isPublic"], "idx_isPublic" ); + } + ); } - } catch ( any e ) { + } catch (any e) { transactionRollback(); systemOutput( e.stacktrace, true ); rethrow; @@ -104,321 +91,100 @@ component { } } - function down( schema, query ){ + function down( schema, query ) { if ( !isContentBox4() ) { return; } // Remove Site Relationships - variables.siteTables.each( ( thisTable ) => { - schema.alter( thisTable, ( table ) => { - table.dropColumn( "FK_siteID" ); - } ); - systemOutput( "√ - Removed site relationship to '#thisTable#'", true ); - } ); + variables.siteTables.each( + ( thisTable ) => { + schema.alter( + thisTable, + ( table ) => { + table.dropColumn( "FK_siteID" ); + } + ); + systemOutput( "√ - Removed site relationship to '#thisTable#'", true ); + } + ); // Remove Site Table arguments.schema.drop( "cb_site" ); // Remove permissions - arguments.query + arguments + .query .newQuery() .from( "cb_permission" ) .where( "permission", "SITES_ADMIN" ) .delete(); } - /********************* MIGRATION UPDATES *************************/ - - private function removeUniqueConstraints( schema, query ){ - // Remove Setting Name Unique Constraint - dropIndexesForTableColumn( "cb_setting", "name" ); - systemOutput( "√ - Setting name unique constraint dropped", true ); - - // Remove Content Unique Constraint - dropIndexesForTableColumn( "cb_content", "slug" ); - systemOutput( "√ - Content slug unique constraint dropped", true ); - - // Remove category unique constraint - dropIndexesForTableColumn( "cb_category", "slug" ); - systemOutput( "√ - Content Category slug unique constraint dropped", true ); - - // Remove menu unique constraint - dropIndexesForTableColumn( "cb_menu", "slug" ); - systemOutput( "√ - Menu slug unique constraint dropped", true ); - } - - private function createSiteRelationships( schema, query, siteId ){ - variables.siteTables.each( ( thisTable ) => { - if ( !hasColumn( thisTable, "FK_siteID" ) ) { - // Add site id relationship - schema.alter( thisTable, ( table ) => { - table.addColumn( table.string( "FK_siteID", 36 ).nullable() ); - table.addConstraint( - table - .foreignKey( "FK_siteID" ) - .references( "siteID" ) - .onTable( "cb_site" ) - .onDelete( "CASCADE" ) - ); - } ); - systemOutput( "√ - Created site column on '#thisTable#'", true ); - } else { - systemOutput( "! - Skipped creating site column on '#thisTable#', it already had one", true ); - } - - // Seed with site id - if ( thisTable != "cb_setting" ) { - query - .newQuery() - .from( thisTable ) - .whereNull( "FK_siteID" ) - .update( { "FK_siteID" : siteId } ); - - systemOutput( "√ - Populated '#thisTable#' with default site data", true ); - } - } ); - } - - /** - * Updates the admin with newer permissions - */ - private function updateAdminPermissions( schema, query ){ - var admin = arguments.query - .newQuery() - .select( "roleID" ) - .from( "cb_role" ) - .where( "role", "Administrator" ) - .first(); - - var siteAdmin = arguments.query - .newQuery() - .select( "permissionID" ) - .from( "cb_permission" ) - .where( "permission", "SITES_ADMIN" ) - .first(); - - var sitePermissionFound = !arguments.query - .newQuery() - .select( "FK_permissionID" ) - .from( "cb_rolePermissions" ) - .where( "FK_permissionID", siteAdmin.permissionID ) - .first() - .isEmpty(); - - if ( !sitePermissionFound ) { - arguments.query - .newQuery() - .from( "cb_rolePermissions" ) - .insert( { - "FK_roleID" : admin.roleID, - "FK_permissionID" : siteAdmin.permissionID - } ); - systemOutput( "√ - Admin role updated with new permissions", true ); - } else { - systemOutput( "√ - Admin role already has the new permissions, skipping", true ); - } - } - - /** - * Creates the new permissions - */ - private function createPermissions( schema, query ){ - variables.newPermissions.each( ( thisPermission ) => { - var isNewPermission = query - .newQuery() - .select( "permissionID" ) - .from( "cb_permission" ) - .where( "permission", thisPermission.name ) - .first() - .isEmpty(); - - if ( !isNewPermission ) { - systemOutput( "√ - #thisPermission.name# permission already in database skipping", true ); - return; - } - - query - .newQuery() - .from( "cb_permission" ) - .insert( { - "permissionID" : uuidLib.randomUUID().toString(), - "createdDate" : today, - "modifiedDate" : today, - "isDeleted" : 0, - "permission" : thisPermission.name, - "description" : thisPermission.description - } ); - systemOutput( "√ - #thisPermission.name# permission created", true ); - } ); - } - - /** - * Create multi-site support - */ - private function createDefaultSite( schema, query ){ - // Create the site table - arguments.schema.create( "cb_site", ( table ) => { - table.string( "siteID", 36 ).primaryKey(); - table.dateTime( "createdDate" ); - table.dateTime( "modifiedDate" ); - table.boolean( "isDeleted" ).default( false ); - table.string( "name" ); - table.string( "slug" ).unique(); - table.longText( "description" ).nullable(); - table.string( "domainRegex" ).nullable(); - table.string( "keywords" ).nullable(); - table.string( "tagline" ).nullable(); - table.string( "homepage" ).nullable(); - table.boolean( "isBlogEnabled" ).default( true ); - table.boolean( "isSitemapEnabled" ).default( true ); - table.boolean( "poweredByHeader" ).default( true ); - table.boolean( "adminBar" ).default( true ); - table.boolean( "isSSL" ).default( false ); - table.string( "activeTheme" ).nullable(); - table.longText( "notificationEmails" ).nullable(); - table.boolean( "notifyOnEntries" ).default( true ); - table.boolean( "notifyOnPages" ).default( true ); - table.boolean( "notifyOnContentStore" ).default( true ); - table.string( "domain" ).nullable(); - table.boolean( "isActive" ).default( true ); - } ); - systemOutput( "√ - Site table created", true ); - - schema.alter( "cb_setting", function( table ){ - table.addColumn( table.string( "FK_siteID", 36 ).nullable() ); - table.addConstraint( - table - .string( "FK_siteID", 36 ) - .references( "siteID" ) - .onTable( "cb_site" ) - ); - } ); - - var allSettings = arguments.query - .newQuery() - .from( "cb_setting" ) - .whereNull( "FK_siteID" ) - .get() - .reduce( ( results, thisSetting ) => { - results[ thisSetting.name ] = thisSetting.value; - return results; - }, {} ); - - var initialSiteIdentifier = uuidLib.randomUUID().toString(); - arguments.query - .newQuery() - .from( "cb_site" ) - .insert( { - "siteID" : initialSiteIdentifier, - "createdDate" : today, - "modifiedDate" : today, - "isDeleted" : 0, - "isActive" : 1, - "name" : allSettings.cb_site_name, - "slug" : "default", - "homepage" : allSettings.cb_site_homepage, - "description" : allSettings.cb_site_description, - "keywords" : allSettings.cb_site_keywords, - "tagline" : allSettings.cb_site_tagline, - "domainRegex" : "127\.0\.0\.1", - "isBlogEnabled" : allSettings.cb_site_disable_blog ? 0 : 1, - "isSitemapEnabled" : allSettings.cb_site_sitemap ? 1 : 0, - "poweredByHeader" : allSettings.cb_site_poweredby ? 1 : 0, - "adminBar" : allSettings.cb_site_adminbar ? 1 : 0, - "isSSL" : allSettings.cb_admin_ssl ? 1 : 0, - "activeTheme" : allSettings.cb_site_theme, - "domain" : "127.0.0.1", - "notificationEmails" : allSettings.cb_site_email - } ); - systemOutput( "√ - Default site created", true ); - - var siteSettings = [ - // Global HTML: Panel Section - "cb_html_beforeHeadEnd", - "cb_html_afterBodyStart", - "cb_html_beforeBodyEnd", - "cb_html_beforeContent", - "cb_html_afterContent", - "cb_html_beforeSideBar", - "cb_html_afterSideBar", - "cb_html_afterFooter", - "cb_html_preEntryDisplay", - "cb_html_postEntryDisplay", - "cb_html_preIndexDisplay", - "cb_html_postIndexDisplay", - "cb_html_preArchivesDisplay", - "cb_html_postArchivesDisplay", - "cb_html_preCommentForm", - "cb_html_postCommentForm", - "cb_html_prePageDisplay", - "cb_html_postPageDisplay", - // Site Comment Settings - "cb_comments_enabled", - "cb_comments_maxDisplayChars", - "cb_comments_notify", - "cb_comments_moderation_notify", - "cb_comments_notifyemails", - "cb_comments_moderation", - "cb_comments_moderation_whitelist", - "cb_comments_moderation_blacklist", - "cb_comments_moderation_blockedlist", - "cb_comments_moderation_expiration" - ]; - - // Assign all null site settings to the default - query - .newQuery() - .from( "cb_setting" ) - .whereIn( "name", siteSettings ) - .update( { "FK_siteID" : initialSiteIdentifier } ); - - return initialSiteIdentifier; - } - /** * Migrate numeric IDs to Guids */ - function migrateIdentifiersToGUIDs( schema, query ){ - systemOutput( "> Starting to process migration of identifiers to uuid's...", true ); + function migrateIdentifiersToGUIDs( schema, query ) { + systemOutput( + "> Starting to process migration of identifiers to uuid's...", + true + ); // Create new master table identifiers with a temp name so we can migrate - variables.idTables + variables + .idTables .keyArray() - .each( function( tableName ){ - var pkColumn = idTables[ tableName ]; - schema.alter( tableName, function( table ){ - table.addColumn( table.string( "id", 36 ).default( "#guidFn#" ) ); - } ); - query - .newQuery() - .from( tableName ) - .update( { "id" : query.raw( "#guidFn#" ) } ); - systemOutput( " √ - #tablename# new uuid pk created and populated", true ); - } ); - - systemOutput( "√√ - Finalized adding new primary keys to all tables", true ); + .each( + function( tableName ) { + var pkColumn = idTables[ tableName ]; + schema.alter( + tableName, + function( table ) { + table.addColumn( table.string( "id", 36 ).default( "#guidFn#" ) ); + } + ); + query + .newQuery() + .from( tableName ) + .update( { "id": query.raw( "#guidFn#" ) } ); + systemOutput( + " √ - #tablename# new uuid pk created and populated", + true + ); + } + ); + + systemOutput( + "√√ - Finalized adding new primary keys to all tables", + true + ); systemOutput( "", true ); systemOutput( "> Beginning to process child tables...", true ); systemOutput( "", true ); // Create child table foreign and future PKs - childTables - .keyArray() - .each( function( tableName ){ - systemOutput( "> Starting to process child table: #tableName#", true ); + childTables.keyArray().each( + function( tableName ) { + systemOutput( "> Starting to process child table: #tableName#", true ); - var pkColumn = childTables[ tableName ].key; - dropForeignKeysAndConstraints( tableName, pkColumn ); - systemOutput( " √ - (#tableName#) Dropped foreign key and constraints", true ); + var pkColumn = childTables[ tableName ].key; + dropForeignKeysAndConstraints( tableName, pkColumn ); + systemOutput( + " √ - (#tableName#) Dropped foreign key and constraints", + true + ); - var tmpColumn = "tmp_" & pkColumn; - schema.alter( tableName, function( table ){ - table.addColumn( table.string( tmpColumn, 36 ).nullable() ); - } ); - populateChildFKValues( tmpColumn, tableName ); - systemOutput( " √ - (#tableName#) rekeyed to new parent uuid", true ); - } ); + var tmpColumn = "tmp_" & pkColumn; + schema.alter( + tableName, + function( table ) { + table.addColumn( table.string( tmpColumn, 36 ).nullable() ); + } + ); + populateChildFKValues( tmpColumn, tableName ); + systemOutput( " √ - (#tableName#) rekeyed to new parent uuid", true ); + } + ); systemOutput( "√√ - Finalized rekeying all child tables", true ); systemOutput( "", true ); @@ -426,80 +192,120 @@ component { systemOutput( "", true ); // Update all foreign keys - FKMap - .keyArray() - .each( function( tableName ){ - systemOutput( "> Starting to process (#arguments.tableName#) foreign keys...", true ); - - var FKeys = FKMap[ arguments.tableName ]; - FKeys.each( function( keyConfig ){ - dropForeignKeysAndConstraints( tableName, arguments.keyConfig.column ); + FKMap.keyArray().each( + function( tableName ) { systemOutput( - " √ - (#tableName#) Dropped foreign key and constraints (#arguments.keyConfig.column#)", + "> Starting to process (#arguments.tableName#) foreign keys...", true ); - var tmpColumn = "tmp_" & arguments.keyConfig.column; - schema.alter( tableName, function( table ){ - table.addColumn( table.string( tmpColumn, 36 ).nullable() ); - } ); - populateFKValues( tmpColumn, tableName, arguments.keyConfig ); - schema.alter( tableName, function( table ){ - table.dropColumn( keyConfig.column ); - table.renameColumn( tmpColumn, table.string( keyConfig.column, 36 ).nullable() ); - } ); - systemOutput( - " √ - (#tableName#) foreign key (#arguments.keyConfig.column#) rekeyed as a uuid into (#tmpColumn#)", - true - ); - } ); - } ); + var FKeys = FKMap[ arguments.tableName ]; + FKeys.each( + function( keyConfig ) { + dropForeignKeysAndConstraints( tableName, arguments.keyConfig.column ); + systemOutput( + " √ - (#tableName#) Dropped foreign key and constraints (#arguments.keyConfig.column#)", + true + ); + + var tmpColumn = "tmp_" & arguments.keyConfig.column; + schema.alter( + tableName, + function( table ) { + table.addColumn( table.string( tmpColumn, 36 ).nullable() ); + } + ); + populateFKValues( + tmpColumn, + tableName, + arguments.keyConfig + ); + schema.alter( + tableName, + function( table ) { + table.dropColumn( keyConfig.column ); + table.renameColumn( tmpColumn, + table.string( keyConfig.column, 36 ).nullable() ); + } + ); + systemOutput( + " √ - (#tableName#) foreign key (#arguments.keyConfig.column#) rekeyed as a uuid into (#tmpColumn#)", + true + ); + } + ); + } + ); - systemOutput( "√√ - Finalized rekeying all foreign keys to new uuid's", true ); + systemOutput( + "√√ - Finalized rekeying all foreign keys to new uuid's", + true + ); systemOutput( "", true ); - systemOutput( "> Beginning to drop original primary keys and rekeying tables with new uuids...", true ); + systemOutput( + "> Beginning to drop original primary keys and rekeying tables with new uuids...", + true + ); systemOutput( "", true ); // Change primary keys over on master tables - idTables - .keyArray() - .each( function( tableName ){ - systemOutput( "> Starting to process (#arguments.tableName#)...", true ); - var pkColumn = idTables[ tableName ]; - schema.alter( tableName, function( table ){ - queryExecute( pkDropSQL( tableName, pkColumn ) ); - table.dropColumn( pkColumn ); - // Rename it back to what it was called - table.renameColumn( "id", table.string( pkColumn, 36 ).unique() ) - table.addConstraint( table.primaryKey( pkColumn ) ); - } ); - systemOutput( " √ (#arguments.tableName#) new uuid key set and finalized!", true ); - } ); - - systemOutput( "√√ - Finalized rekeying all tables with new identifiers and old identifiers dropped", true ); + idTables.keyArray().each( + function( tableName ) { + systemOutput( "> Starting to process (#arguments.tableName#)...", true ); + var pkColumn = idTables[ tableName ]; + schema.alter( + tableName, + function( table ) { + queryExecute( pkDropSQL( tableName, pkColumn ) ); + table.dropColumn( pkColumn ); + + table.renameColumn( "id", table.string( pkColumn, 36 ).unique() ); + table.addConstraint( table.primaryKey( pkColumn ) ); + } + ); + systemOutput( + " √ (#arguments.tableName#) new uuid key set and finalized!", + true + ); + } + ); + + systemOutput( + "√√ - Finalized rekeying all tables with new identifiers and old identifiers dropped", + true + ); systemOutput( "", true ); - systemOutput( "> Beginning restore all foreign key constraints...", true ); + systemOutput( + "> Beginning restore all foreign key constraints...", + true + ); systemOutput( "", true ); // Now restore the foreign key constraints - FKMap - .keyArray() - .each( function( tableName ){ - systemOutput( "> Starting to process (#arguments.tableName#)...", true ); - var FKeys = FKMap[ tableName ]; - FKeys.each( function( keyConfig ){ - var tmpColumn = "tmp_" & keyConfig.column; - schema.alter( tableName, function( table ){ - table.addConstraint( - table - .string( keyConfig.column, 36 ) - .references( keyConfig.reference.column ) - .onTable( keyConfig.reference.table ) + FKMap.keyArray().each( + function( tableName ) { + systemOutput( "> Starting to process (#arguments.tableName#)...", true ); + var FKeys = FKMap[ tableName ]; + FKeys.each( + function( keyConfig ) { + var tmpColumn = "tmp_" & keyConfig.column; + schema.alter( + tableName, + function( table ) { + table.addConstraint( table + .string( keyConfig.column, 36 ) + .references( keyConfig.reference.column ) + .onTable( keyConfig.reference.table ) ); + } + ); + } ); - } ); - } ); - systemOutput( " √ (#arguments.tableName#) foreign key constraints finalized!", true ); - } ); + systemOutput( + " √ (#arguments.tableName#) foreign key constraints finalized!", + true + ); + } + ); systemOutput( "√√ - All foreign key constraints finalized", true ); systemOutput( "", true ); @@ -507,36 +313,52 @@ component { systemOutput( "", true ); // Change primary keys over on child tables - childTables - .keyArray() - .each( function( tableName ){ - systemOutput( "> Processing child table (#arguments.tableName#)...", true ); - var pkColumn = childTables[ tableName ].key; - var tmpColumn = "tmp_" & pkColumn; - schema.alter( tableName, function( table ){ - queryExecute( pkDropSQL( tableName, pkColumn ) ); - // ensure it is a not null field before we make it PK - table.modifyColumn( tmpColumn, table.string( tmpColumn, 36 ) ); - } ); - schema.alter( tableName, function( table ){ - table.addConstraint( table.primaryKey( tmpColumn ) ); - } ); - schema.alter( tableName, function( table ){ - table.dropColumn( pkColumn ); - table.renameColumn( tmpColumn, table.string( pkColumn, 36 ) ); - } ); - schema.alter( tableName, function( table ){ - table.addConstraint( - table - .string( pkColumn, 36 ) - .references( pkColumn ) - .onTable( childTables[ tableName ].parent ) + childTables.keyArray().each( + function( tableName ) { + systemOutput( + "> Processing child table (#arguments.tableName#)...", + true ); - } ); - systemOutput( " √ (#arguments.tableName#) finalized!", true ); - } ); + var pkColumn = childTables[ tableName ].key; + var tmpColumn = "tmp_" & pkColumn; + schema.alter( + tableName, + function( table ) { + queryExecute( pkDropSQL( tableName, pkColumn ) ); + + table.modifyColumn( tmpColumn, table.string( tmpColumn, 36 ) ); + } + ); + schema.alter( + tableName, + function( table ) { + table.addConstraint( table.primaryKey( tmpColumn ) ); + } + ); + schema.alter( + tableName, + function( table ) { + table.dropColumn( pkColumn ); + table.renameColumn( tmpColumn, table.string( pkColumn, 36 ) ); + } + ); + schema.alter( + tableName, + function( table ) { + table.addConstraint( table + .string( pkColumn, 36 ) + .references( pkColumn ) + .onTable( childTables[ tableName ].parent ) ); + } + ); + systemOutput( " √ (#arguments.tableName#) finalized!", true ); + } + ); - systemOutput( "√√√ - All tables migrated from incremental identifiers to GUIDs", true ); + systemOutput( + "√√√ - All tables migrated from incremental identifiers to GUIDs", + true + ); systemOutput( "", true ); systemOutput( "", true ); } @@ -544,166 +366,166 @@ component { /** * Utility functions per database */ - function scopeGrammarUDFs( query, schema ){ + function scopeGrammarUDFs( query, schema ) { variables.idTables = { - "cb_author" : "authorID", - "cb_category" : "categoryID", - "cb_comment" : "commentID", - "cb_content" : "contentID", - "cb_contentVersion" : "contentVersionID", - "cb_customfield" : "customFieldID", - "cb_loginAttempts" : "loginAttemptsID", - "cb_menu" : "menuID", - "cb_menuItem" : "menuItemID", - "cb_module" : "moduleID", - "cb_permission" : "permissionID", - "cb_permissionGroup" : "permissionGroupID", - "cb_role" : "roleID", - "cb_securityRule" : "ruleID", - "cb_setting" : "settingID", - "cb_stats" : "statsID", - "cb_subscribers" : "subscriberID", - "cb_subscriptions" : "subscriptionID" + "cb_author" : "authorID", + "cb_category" : "categoryID", + "cb_comment" : "commentID", + "cb_content" : "contentID", + "cb_contentVersion" : "contentVersionID", + "cb_customfield" : "customFieldID", + "cb_loginAttempts" : "loginAttemptsID", + "cb_menu" : "menuID", + "cb_menuItem" : "menuItemID", + "cb_module" : "moduleID", + "cb_permission" : "permissionID", + "cb_permissionGroup": "permissionGroupID", + "cb_role" : "roleID", + "cb_securityRule" : "ruleID", + "cb_setting" : "settingID", + "cb_stats" : "statsID", + "cb_subscribers" : "subscriberID", + "cb_subscriptions" : "subscriptionID" }; variables.childTables = { - "cb_entry" : { "parent" : "cb_content", "key" : "contentID" }, - "cb_page" : { "parent" : "cb_content", "key" : "contentID" }, - "cb_contentStore" : { "parent" : "cb_content", "key" : "contentID" }, - "cb_commentSubscriptions" : { "parent" : "cb_subscriptions", "key" : "subscriptionID" } + "cb_entry" : { "parent": "cb_content", "key": "contentID" }, + "cb_page" : { "parent": "cb_content", "key": "contentID" }, + "cb_contentStore" : { "parent": "cb_content", "key": "contentID" }, + "cb_commentSubscriptions": { "parent": "cb_subscriptions", "key": "subscriptionID" } }; variables.FKMap = { - "cb_authorPermissionGroups" : [ + "cb_authorPermissionGroups": [ { - "column" : "FK_permissionGroupID", - "reference" : { - "table" : "cb_permissionGroup", - "column" : "permissionGroupID" + "column" : "FK_permissionGroupID", + "reference": { + "table" : "cb_permissionGroup", + "column": "permissionGroupID" } }, { - "column" : "FK_authorID", - "reference" : { "table" : "cb_author", "column" : "authorID" } + "column" : "FK_authorID", + "reference": { "table": "cb_author", "column": "authorID" } } ], - "cb_authorPermissions" : [ + "cb_authorPermissions": [ { - "column" : "FK_permissionID", - "reference" : { "table" : "cb_permission", "column" : "permissionID" } + "column" : "FK_permissionID", + "reference": { "table": "cb_permission", "column": "permissionID" } }, { - "column" : "FK_authorID", - "reference" : { "table" : "cb_author", "column" : "authorID" } + "column" : "FK_authorID", + "reference": { "table": "cb_author", "column": "authorID" } } ], - "cb_rolePermissions" : [ + "cb_rolePermissions": [ { - "column" : "FK_permissionID", - "reference" : { "table" : "cb_permission", "column" : "permissionID" } + "column" : "FK_permissionID", + "reference": { "table": "cb_permission", "column": "permissionID" } }, { - "column" : "FK_roleID", - "reference" : { "table" : "cb_role", "column" : "roleID" } + "column" : "FK_roleID", + "reference": { "table": "cb_role", "column": "roleID" } } ], - "cb_relatedContent" : [ + "cb_relatedContent": [ { - "column" : "FK_contentID", - "reference" : { "table" : "cb_content", "column" : "contentID" } + "column" : "FK_contentID", + "reference": { "table": "cb_content", "column": "contentID" } }, { - "column" : "FK_relatedContentID", - "reference" : { "table" : "cb_content", "column" : "contentID" } + "column" : "FK_relatedContentID", + "reference": { "table": "cb_content", "column": "contentID" } } ], - "cb_groupPermissions" : [ + "cb_groupPermissions": [ { - "column" : "FK_permissionGroupID", - "reference" : { - "table" : "cb_permissionGroup", - "column" : "permissionGroupID" + "column" : "FK_permissionGroupID", + "reference": { + "table" : "cb_permissionGroup", + "column": "permissionGroupID" } }, { - "column" : "FK_permissionID", - "reference" : { "table" : "cb_permission", "column" : "permissionID" } + "column" : "FK_permissionID", + "reference": { "table": "cb_permission", "column": "permissionID" } } ], - "cb_contentCategories" : [ + "cb_contentCategories": [ { - "column" : "FK_contentID", - "reference" : { "table" : "cb_content", "column" : "contentID" } + "column" : "FK_contentID", + "reference": { "table": "cb_content", "column": "contentID" } }, { - "column" : "FK_categoryID", - "reference" : { "table" : "cb_category", "column" : "categoryID" } + "column" : "FK_categoryID", + "reference": { "table": "cb_category", "column": "categoryID" } } ], - "cb_commentSubscriptions" : [ + "cb_commentSubscriptions": [ { - "column" : "FK_contentID", - "reference" : { "table" : "cb_content", "column" : "contentID" } + "column" : "FK_contentID", + "reference": { "table": "cb_content", "column": "contentID" } } ], - "cb_author" : [ + "cb_author": [ { - "column" : "FK_roleID", - "reference" : { "table" : "cb_role", "column" : "roleID" } + "column" : "FK_roleID", + "reference": { "table": "cb_role", "column": "roleID" } } ], - "cb_menuItem" : [ + "cb_menuItem": [ { - "column" : "FK_menuID", - "reference" : { "table" : "cb_menu", "column" : "menuID" } + "column" : "FK_menuID", + "reference": { "table": "cb_menu", "column": "menuID" } }, { - "column" : "FK_parentID", - "reference" : { "table" : "cb_menuItem", "column" : "menuItemID" } + "column" : "FK_parentID", + "reference": { "table": "cb_menuItem", "column": "menuItemID" } } ], - "cb_customField" : [ + "cb_customField": [ { - "column" : "FK_contentID", - "reference" : { "table" : "cb_content", "column" : "contentID" } + "column" : "FK_contentID", + "reference": { "table": "cb_content", "column": "contentID" } } ], - "cb_stats" : [ + "cb_stats": [ { - "column" : "FK_contentID", - "reference" : { "table" : "cb_content", "column" : "contentID" } + "column" : "FK_contentID", + "reference": { "table": "cb_content", "column": "contentID" } } ], - "cb_comment" : [ + "cb_comment": [ { - "column" : "FK_contentID", - "reference" : { "table" : "cb_content", "column" : "contentID" } + "column" : "FK_contentID", + "reference": { "table": "cb_content", "column": "contentID" } } ], - "cb_content" : [ + "cb_content": [ { - "column" : "FK_authorID", - "reference" : { "table" : "cb_author", "column" : "authorID" } + "column" : "FK_authorID", + "reference": { "table": "cb_author", "column": "authorID" } }, { - "column" : "FK_parentID", - "reference" : { "table" : "cb_content", "column" : "contentID" } + "column" : "FK_parentID", + "reference": { "table": "cb_content", "column": "contentID" } } ], - "cb_contentVersion" : [ + "cb_contentVersion": [ { - "column" : "FK_authorID", - "reference" : { "table" : "cb_author", "column" : "authorID" } + "column" : "FK_authorID", + "reference": { "table": "cb_author", "column": "authorID" } }, { - "column" : "FK_contentID", - "reference" : { "table" : "cb_content", "column" : "contentID" } + "column" : "FK_contentID", + "reference": { "table": "cb_content", "column": "contentID" } } ], - "cb_subscriptions" : [ + "cb_subscriptions": [ { - "column" : "FK_subscriberID", - "reference" : { "table" : "cb_subscribers", "column" : "subscriberID" } + "column" : "FK_subscriberID", + "reference": { "table": "cb_subscribers", "column": "subscriberID" } } ] }; @@ -715,19 +537,25 @@ component { switch ( listLast( getMetadata( grammar ).name, "." ) ) { case "MySQLGrammar": { - variables.guidFn = "UUID()"; - variables.populateFKValues = function( tmpColumn, tableName, keyConfig ){ + variables.guidFn = "UUID()"; + variables.populateFKValues = function( tmpColumn, tableName, keyConfig ) { queryExecute( " UPDATE #arguments.tableName# as target - JOIN #arguments.keyConfig.reference.table# as ref - ON target.#arguments.keyConfig.column# = ref.#arguments.keyConfig.reference.column# + JOIN #arguments + .keyConfig + .reference + .table# as ref + ON target.#arguments.keyConfig.column# = ref.#arguments + .keyConfig + .reference + .column# SET target.#arguments.tmpColumn# = ref.id " ); }; - variables.populateChildFKValues = function( tmpColumn, tableName ){ + variables.populateChildFKValues = function( tmpColumn, tableName ) { queryExecute( " UPDATE #arguments.tableName# @@ -739,95 +567,133 @@ component { ); }; - variables.pkDropSQL = function( tableName, pkColumn ){ + variables.pkDropSQL = function( tableName, pkColumn ) { return "ALTER TABLE #arguments.tableName# DROP PRIMARY KEY, MODIFY #arguments.pkColumn# int(11)"; - } + }; - variables.dropForeignKeysAndConstraints = function( tableName, columnName, dropReferenced = true ){ + variables.dropForeignKeysAndConstraints = function( tableName, columnName, dropReferenced = true ) { // Drop FKs query .newQuery() - .select( [ "CONSTRAINT_NAME" ] ) + .select( [ "CONSTRAINT_NAME"] ) .from( "INFORMATION_SCHEMA.KEY_COLUMN_USAGE" ) .where( "TABLE_NAME", tableName ) .where( "COLUMN_NAME", columnName ) - .where( "CONSTRAINT_NAME", "!=", "PRIMARY" ) + .where( + "CONSTRAINT_NAME", + "!=", + "PRIMARY" + ) .where( "TABLE_SCHEMA", variables.dbSchema ) .whereNotNull( "REFERENCED_TABLE_NAME" ) .get() - .map( function( row ){ - return row.constraint_name; - } ) - .each( function( constraintName ){ - queryExecute( "ALTER TABLE #tableName# DROP FOREIGN KEY #constraintName#" ); - } ); + .map( + function( row ) { + return row.constraint_name; + } + ) + .each( + function( constraintName ) { + queryExecute( + "ALTER TABLE #tableName# DROP FOREIGN KEY #constraintName#" + ); + } + ); // Drop Indexes query .newQuery() - .select( [ "INDEX_NAME" ] ) + .select( [ "INDEX_NAME"] ) .from( "INFORMATION_SCHEMA.STATISTICS" ) .where( "TABLE_NAME", tableName ) .where( "COLUMN_NAME", columnName ) - .where( "INDEX_NAME", "!=", "PRIMARY" ) + .where( + "INDEX_NAME", + "!=", + "PRIMARY" + ) .where( "TABLE_SCHEMA", variables.dbSchema ) .get() - .map( function( row ){ - return row.index_name; - } ) - .each( function( indexName ){ - schema.alter( tableName, function( table ){ - table.dropConstraint( indexName ); - } ); - } ); + .map( function( row ) { + return row.index_name; + } ) + .each( + function( indexName ) { + schema.alter( + tableName, + function( table ) { + table.dropConstraint( indexName ); + } + ); + } + ); // Drop any foreign keys which reference this table if ( arguments.dropReferenced && idTables.keyExists( tableName ) ) { query .newQuery() - .select( [ "CONSTRAINT_NAME", "TABLE_NAME" ] ) + .select( [ "CONSTRAINT_NAME", "TABLE_NAME"] ) .from( "INFORMATION_SCHEMA.KEY_COLUMN_USAGE" ) .where( "REFERENCED_TABLE_NAME", tableName ) .where( "REFERENCED_COLUMN_NAME", idTables[ tableName ] ) - .where( "CONSTRAINT_NAME", "!=", "PRIMARY" ) + .where( + "CONSTRAINT_NAME", + "!=", + "PRIMARY" + ) .where( "TABLE_SCHEMA", variables.dbSchema ) .whereNotNull( "TABLE_NAME" ) .get() - .map( function( row ){ - return { - "table" : row.table_name, - "constraint" : row.constraint_name - }; - } ) - .each( function( row ){ - queryExecute( "ALTER TABLE #row.table# DROP FOREIGN KEY #row.constraint#" ); - } ); + .map( + function( row ) { + return { + "table" : row.table_name, + "constraint": row.constraint_name + }; + } + ) + .each( + function( row ) { + queryExecute( + "ALTER TABLE #row.table# DROP FOREIGN KEY #row.constraint#" + ); + } + ); } }; - variables.dropIndexesForTableColumn = function( tableName, columnName ){ + variables.dropIndexesForTableColumn = function( tableName, columnName ) { query .newQuery() - .select( [ "INDEX_NAME" ] ) + .select( [ "INDEX_NAME"] ) .from( "INFORMATION_SCHEMA.STATISTICS" ) .where( "TABLE_NAME", tableName ) .where( "COLUMN_NAME", columnName ) - .where( "INDEX_NAME", "!=", "PRIMARY" ) + .where( + "INDEX_NAME", + "!=", + "PRIMARY" + ) .where( "TABLE_SCHEMA", variables.dbSchema ) .get() - .map( function( row ){ - return row.index_name; - } ) - .each( function( indexName ){ - schema.alter( tableName, function( table ){ - table.dropConstraint( indexName ); - } ); - } ); - } + .map( function( row ) { + return row.index_name; + } ) + .each( + function( indexName ) { + schema.alter( + tableName, + function( table ) { + table.dropConstraint( indexName ); + } + ); + } + ); + }; break; } case "SqlServerGrammar": { - variables.guidFn = "NEWID()"; - variables.pkDropSQL = function( tableName ){ + variables.guidFn = "NEWID()"; + variables.pkDropSQL = function( tableName ) { var constraintName = queryExecute( "SELECT name FROM sys.key_constraints @@ -835,20 +701,26 @@ component { ).name; return "ALTER TABLE #tableName# DROP CONSTRAINT #constraintName#"; - } - variables.populateFKValues = function( tmpColumn, tableName, keyConfig ){ + }; + variables.populateFKValues = function( tmpColumn, tableName, keyConfig ) { queryExecute( " UPDATE target SET target.#arguments.tmpColumn# = ref.id FROM #arguments.tableName# as target - JOIN #arguments.keyConfig.reference.table# as ref - ON target.#arguments.keyConfig.column# = ref.#arguments.keyConfig.reference.column# + JOIN #arguments + .keyConfig + .reference + .table# as ref + ON target.#arguments.keyConfig.column# = ref.#arguments + .keyConfig + .reference + .column# " ); }; - variables.populateChildFKValues = function( tmpColumn, tableName ){ + variables.populateChildFKValues = function( tmpColumn, tableName ) { queryExecute( " UPDATE #arguments.tableName# @@ -861,10 +733,10 @@ component { ); }; - variables.dropForeignKeysAndConstraints = function( tableName, columnName, dropReferenced = true ){ + variables.dropForeignKeysAndConstraints = function( tableName, columnName, dropReferenced = true ) { query .newQuery() - .select( [ "sys.foreign_keys.name" ] ) + .select( [ "sys.foreign_keys.name"] ) .from( "sys.foreign_keys" ) .join( "sys.foreign_key_columns", @@ -876,21 +748,27 @@ component { "sys.tables.OBJECT_ID", "sys.foreign_keys.referenced_object_id" ) - .whereRaw( "OBJECT_NAME( sys.foreign_keys.parent_object_id ) = '#tableName#'" ) + .whereRaw( + "OBJECT_NAME( sys.foreign_keys.parent_object_id ) = '#tableName#'" + ) .whereRaw( "COL_NAME(sys.foreign_key_columns.parent_object_id,sys.foreign_key_columns.parent_column_id) = '#columnName#'" ) .get() - .map( function( row ){ - return row.name; - } ) - .each( function( constraintName ){ - queryExecute( "ALTER TABLE #tableName# DROP CONSTRAINT #constraintName#" ); - } ); + .map( function( row ) { + return row.name; + } ) + .each( + function( constraintName ) { + queryExecute( + "ALTER TABLE #tableName# DROP CONSTRAINT #constraintName#" + ); + } + ); query .newQuery() - .select( [ "name" ] ) + .select( [ "name"] ) .from( "sys.indexes" ) .join( "sys.index_columns", @@ -902,14 +780,18 @@ component { "sys.indexes.object_id = OBJECT_ID( '#tableName#' ) and COL_NAME(sys.index_columns.object_id,sys.index_columns.column_id) = '#columnName#' AND name NOT LIKE 'PK_%'" ) .get() - .map( function( row ){ - return row.name; - } ) - .each( function( indexName ){ - queryExecute( - listFirst( indexName, "_" ) == "UQ" ? "ALTER TABLE #tableName# DROP CONSTRAINT #indexName#" : "DROP INDEX IF EXISTS #indexName# on #tableName#" - ); - } ); + .map( function( row ) { + return row.name; + } ) + .each( + function( indexName ) { + queryExecute( + listFirst( indexName, "_" ) == "UQ" + ? "ALTER TABLE #tableName# DROP CONSTRAINT #indexName#" + : "DROP INDEX IF EXISTS #indexName# on #tableName#" + ); + } + ); // Drop any foreign keys which reference this table if ( arguments.dropReferenced && idTables.keyExists( tableName ) ) { @@ -929,24 +811,32 @@ component { "sys.tables.OBJECT_ID", "sys.foreign_keys.referenced_object_id" ) - .whereRaw( "OBJECT_NAME (sys.foreign_keys.referenced_object_id) = '#tableName#'" ) + .whereRaw( + "OBJECT_NAME (sys.foreign_keys.referenced_object_id) = '#tableName#'" + ) .get() - .map( function( row ){ - return { - "table" : row.table_name, - "constraint" : row.constraint_name - }; - } ) - .each( function( row ){ - queryExecute( "ALTER TABLE #row.table# DROP CONSTRAINT #row.constraint#" ); - } ); + .map( + function( row ) { + return { + "table" : row.table_name, + "constraint": row.constraint_name + }; + } + ) + .each( + function( row ) { + queryExecute( + "ALTER TABLE #row.table# DROP CONSTRAINT #row.constraint#" + ); + } + ); } - } + }; - variables.dropIndexesForTableColumn = function( tableName, columnName ){ + variables.dropIndexesForTableColumn = function( tableName, columnName ) { query .newQuery() - .select( [ "name" ] ) + .select( [ "name"] ) .from( "sys.indexes" ) .join( "sys.index_columns", @@ -958,23 +848,27 @@ component { "sys.indexes.object_id = OBJECT_ID( '#tableName#' ) and COL_NAME(sys.index_columns.object_id,sys.index_columns.column_id) = '#columnName#' AND sys.indexes.type > 2" ) .get() - .map( function( row ){ - return row.name; - } ) - .each( function( indexName ){ - // These may be either constraints or indexes, depending. Try both - try { - queryExecute( "ALTER TABLE #tableName# DROP CONSTRAINT #indexName#" ); - } catch ( any e ) { - queryExecute( "DROP INDEX #indexName# on #tableName#" ); + .map( function( row ) { + return row.name; + } ) + .each( + function( indexName ) { + try { + queryExecute( "ALTER TABLE #tableName# DROP CONSTRAINT #indexName#" ); + } catch (any e) { + queryExecute( "DROP INDEX #indexName# on #tableName#" ); + } } - } ); - } + ); + }; break; } case "PostgresGrammar": + case "OracleGrammar": { - throw( "Database Migrations from ContentBox v4 to v5 are not supported for this DBMS platform" ); + throw( + "Database Migrations from ContentBox v4 to v5 are not supported for this DBMS platform" + ); } default: { throw( @@ -984,4 +878,302 @@ component { } } -} + private function isContentBox4() { + try { + return !hasColumn( "cb_setting", "FK_siteID" ); + } catch (any e) { + // check if we don't have a database yet. + if ( findNoCase( "there is no table", e.message ) ) { + return false; + } else { + rethrow; + } + } + } + + /********************* MIGRATION UPDATES *************************/ + + private function removeUniqueConstraints( schema, query ) { + // Remove Setting Name Unique Constraint + dropIndexesForTableColumn( "cb_setting", "name" ); + systemOutput( "√ - Setting name unique constraint dropped", true ); + + // Remove Content Unique Constraint + dropIndexesForTableColumn( "cb_content", "slug" ); + systemOutput( "√ - Content slug unique constraint dropped", true ); + + // Remove category unique constraint + dropIndexesForTableColumn( "cb_category", "slug" ); + systemOutput( + "√ - Content Category slug unique constraint dropped", + true + ); + + // Remove menu unique constraint + dropIndexesForTableColumn( "cb_menu", "slug" ); + systemOutput( "√ - Menu slug unique constraint dropped", true ); + } + + private function createSiteRelationships( schema, query, siteId ) { + variables.siteTables.each( + ( thisTable ) => { + if ( !hasColumn( thisTable, "FK_siteID" ) ) { + schema.alter( + thisTable, + ( table ) => { + table.addColumn( table.string( "FK_siteID", 36 ).nullable() ); + table.addConstraint( table + .foreignKey( "FK_siteID" ) + .references( "siteID" ) + .onTable( "cb_site" ) + .onDelete( "CASCADE" ) ); + } + ); + systemOutput( "√ - Created site column on '#thisTable#'", true ); + } else { + systemOutput( + "! - Skipped creating site column on '#thisTable#', it already had one", + true + ); + } + + if ( thisTable != "cb_setting" ) { + query + .newQuery() + .from( thisTable ) + .whereNull( "FK_siteID" ) + .update( { "FK_siteID": siteId } ); + + systemOutput( + "√ - Populated '#thisTable#' with default site data", + true + ); + } + } + ); + } + + /** + * Updates the admin with newer permissions + */ + private function updateAdminPermissions( schema, query ) { + var admin = arguments + .query + .newQuery() + .select( "roleID" ) + .from( "cb_role" ) + .where( "role", "Administrator" ) + .first(); + + var siteAdmin = arguments + .query + .newQuery() + .select( "permissionID" ) + .from( "cb_permission" ) + .where( "permission", "SITES_ADMIN" ) + .first(); + + var sitePermissionFound = !arguments + .query + .newQuery() + .select( "FK_permissionID" ) + .from( "cb_rolePermissions" ) + .where( "FK_permissionID", siteAdmin.permissionID ) + .first() + .isEmpty(); + + if ( !sitePermissionFound ) { + arguments + .query + .newQuery() + .from( "cb_rolePermissions" ) + .insert( + { + "FK_roleID" : admin.roleID, + "FK_permissionID": siteAdmin.permissionID + } + ); + systemOutput( "√ - Admin role updated with new permissions", true ); + } else { + systemOutput( + "√ - Admin role already has the new permissions, skipping", + true + ); + } + } + + /** + * Creates the new permissions + */ + private function createPermissions( schema, query ) { + variables.newPermissions.each( + ( thisPermission ) => { + var isNewPermission = query + .newQuery() + .select( "permissionID" ) + .from( "cb_permission" ) + .where( "permission", thisPermission.name ) + .first() + .isEmpty(); + + if ( !isNewPermission ) { + systemOutput( + "√ - #thisPermission.name# permission already in database skipping", + true + ); + return; + } + + query + .newQuery() + .from( "cb_permission" ) + .insert( + { + "permissionID": uuidLib.randomUUID().toString(), + "createdDate" : today, + "modifiedDate": today, + "isDeleted" : 0, + "permission" : thisPermission.name, + "description" : thisPermission.description + } + ); + systemOutput( "√ - #thisPermission.name# permission created", true ); + } + ); + } + + /** + * Create multi-site support + */ + private function createDefaultSite( schema, query ) { + // Create the site table + arguments.schema.create( + "cb_site", + ( table ) => { + table.string( "siteID", 36 ).primaryKey(); + table.dateTime( "createdDate" ); + table.dateTime( "modifiedDate" ); + table.boolean( "isDeleted" ).default( false ); + table.string( "name" ); + table.string( "slug" ).unique(); + table.longText( "description" ).nullable(); + table.string( "domainRegex" ).nullable(); + table.string( "keywords" ).nullable(); + table.string( "tagline" ).nullable(); + table.string( "homepage" ).nullable(); + table.boolean( "isBlogEnabled" ).default( true ); + table.boolean( "isSitemapEnabled" ).default( true ); + table.boolean( "poweredByHeader" ).default( true ); + table.boolean( "adminBar" ).default( true ); + table.boolean( "isSSL" ).default( false ); + table.string( "activeTheme" ).nullable(); + table.longText( "notificationEmails" ).nullable(); + table.boolean( "notifyOnEntries" ).default( true ); + table.boolean( "notifyOnPages" ).default( true ); + table.boolean( "notifyOnContentStore" ).default( true ); + table.string( "domain" ).nullable(); + table.boolean( "isActive" ).default( true ); + } + ); + systemOutput( "√ - Site table created", true ); + + schema.alter( + "cb_setting", + function( table ) { + table.addColumn( table.string( "FK_siteID", 36 ).nullable() ); + table.addConstraint( table + .string( "FK_siteID", 36 ) + .references( "siteID" ) + .onTable( "cb_site" ) ); + } + ); + + var allSettings = arguments + .query + .newQuery() + .from( "cb_setting" ) + .whereNull( "FK_siteID" ) + .get() + .reduce( + ( results, thisSetting ) => { + results[ thisSetting.name ] = thisSetting.value; + return results; + }, + {} + ); + + var initialSiteIdentifier = uuidLib.randomUUID().toString(); + arguments + .query + .newQuery() + .from( "cb_site" ) + .insert( + { + "siteID" : initialSiteIdentifier, + "createdDate" : today, + "modifiedDate" : today, + "isDeleted" : 0, + "isActive" : 1, + "name" : allSettings.cb_site_name, + "slug" : "default", + "homepage" : allSettings.cb_site_homepage, + "description" : allSettings.cb_site_description, + "keywords" : allSettings.cb_site_keywords, + "tagline" : allSettings.cb_site_tagline, + "domainRegex" : "127\.0\.0\.1", + "isBlogEnabled" : allSettings.cb_site_disable_blog ? 0 : 1, + "isSitemapEnabled" : allSettings.cb_site_sitemap ? 1 : 0, + "poweredByHeader" : allSettings.cb_site_poweredby ? 1 : 0, + "adminBar" : allSettings.cb_site_adminbar ? 1 : 0, + "isSSL" : allSettings.cb_admin_ssl ? 1 : 0, + "activeTheme" : allSettings.cb_site_theme, + "domain" : "127.0.0.1", + "notificationEmails": allSettings.cb_site_email + } + ); + systemOutput( "√ - Default site created", true ); + + var siteSettings = [ + // Global HTML: Panel Section + "cb_html_beforeHeadEnd", + "cb_html_afterBodyStart", + "cb_html_beforeBodyEnd", + "cb_html_beforeContent", + "cb_html_afterContent", + "cb_html_beforeSideBar", + "cb_html_afterSideBar", + "cb_html_afterFooter", + "cb_html_preEntryDisplay", + "cb_html_postEntryDisplay", + "cb_html_preIndexDisplay", + "cb_html_postIndexDisplay", + "cb_html_preArchivesDisplay", + "cb_html_postArchivesDisplay", + "cb_html_preCommentForm", + "cb_html_postCommentForm", + "cb_html_prePageDisplay", + "cb_html_postPageDisplay", + // Site Comment Settings + "cb_comments_enabled", + "cb_comments_maxDisplayChars", + "cb_comments_notify", + "cb_comments_moderation_notify", + "cb_comments_notifyemails", + "cb_comments_moderation", + "cb_comments_moderation_whitelist", + "cb_comments_moderation_blacklist", + "cb_comments_moderation_blockedlist", + "cb_comments_moderation_expiration" + ]; + + // Assign all null site settings to the default + query + .newQuery() + .from( "cb_setting" ) + .whereIn( "name", siteSettings ) + .update( { "FK_siteID": initialSiteIdentifier } ); + + return initialSiteIdentifier; + } + +} \ No newline at end of file diff --git a/modules/contentbox/migrations/2022_03_07_155812_v5_1_0_page_sslonly_removals.cfc b/modules/contentbox/migrations/2022_03_07_155812_v5_1_0_page_sslonly_removals.cfc index 9cab82c06a..9d653f85d5 100755 --- a/modules/contentbox/migrations/2022_03_07_155812_v5_1_0_page_sslonly_removals.cfc +++ b/modules/contentbox/migrations/2022_03_07_155812_v5_1_0_page_sslonly_removals.cfc @@ -7,24 +7,29 @@ * @author Davis Vega */ component { - // DI property name="migrationService" inject="MigrationService@cfmigrations"; - // Include Utils include template="./util/MigrationUtils.cfm"; - function up( schema, qb ){ + function up( schema, qb ) { if ( hasColumn( "cb_page", "SSLOnly" ) ) { - schema.alter( "cb_page", ( table ) => { - table.dropColumn( "SSLOnly" ); - } ); + schema.alter( + "cb_page", + ( table ) => { + table.dropColumn( "SSLOnly" ); + } + ); } else { - systemOutput( "- skipping 'sslonly' removal, cb_page doesn't have the column", true ); + systemOutput( + "- skipping 'sslonly' removal, cb_page doesn't have the column", + true + ); } } - function down( schema, qb ){ + function down( schema, qb ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/2022_04_20_143337_v5_3_0_deprecateMobileLayout.cfc b/modules/contentbox/migrations/2022_04_20_143337_v5_3_0_deprecateMobileLayout.cfc index a0d65113c6..56c80dcec8 100644 --- a/modules/contentbox/migrations/2022_04_20_143337_v5_3_0_deprecateMobileLayout.cfc +++ b/modules/contentbox/migrations/2022_04_20_143337_v5_3_0_deprecateMobileLayout.cfc @@ -6,25 +6,30 @@ * @author Daniel Garcia */ component { - // DI property name="migrationService" inject="MigrationService@cfmigrations"; - // Include Utils include template="./util/MigrationUtils.cfm"; - function up( schema, qb ){ + function up( schema, qb ) { if ( hasColumn( "cb_page", "mobileLayout" ) ) { // Remove the mobileLayout column from the `cb_page` table - schema.alter( "cb_page", ( table ) => { - table.dropColumn( "mobileLayout" ); - } ); + schema.alter( + "cb_page", + ( table ) => { + table.dropColumn( "mobileLayout" ); + } + ); } else { - systemOutput( "- skipping 'mobileLayout' removal, cb_page doesn't have the column", true ); + systemOutput( + "- skipping 'mobileLayout' removal, cb_page doesn't have the column", + true + ); } } - function down( schema, qb ){ + function down( schema, qb ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/2022_05_27_133613_v_5_3_0_CONTENTBOX-1437-Drop-cacheLayout-Column.cfc b/modules/contentbox/migrations/2022_05_27_133613_v_5_3_0_CONTENTBOX-1437-Drop-cacheLayout-Column.cfc index 166440901e..7b8786bea6 100755 --- a/modules/contentbox/migrations/2022_05_27_133613_v_5_3_0_CONTENTBOX-1437-Drop-cacheLayout-Column.cfc +++ b/modules/contentbox/migrations/2022_05_27_133613_v_5_3_0_CONTENTBOX-1437-Drop-cacheLayout-Column.cfc @@ -6,24 +6,29 @@ * @author Jon Clausen */ component { - // DI property name="migrationService" inject="MigrationService@cfmigrations"; - // Include Utils include template="./util/MigrationUtils.cfm"; - function up( schema, qb ){ + function up( schema, qb ) { if ( hasColumn( "cb_content", "cacheLayout" ) ) { - schema.alter( "cb_content", ( table ) => { - table.dropColumn( "cacheLayout" ); - } ); + schema.alter( + "cb_content", + ( table ) => { + table.dropColumn( "cacheLayout" ); + } + ); } else { - systemOutput( "- skipping 'cacheLayout' removal, cb_content doesn't have the column", true ); + systemOutput( + "- skipping 'cacheLayout' removal, cb_content doesn't have the column", + true + ); } } - function down( schema, qb ){ + function down( schema, qb ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/2022_08_05_153052_v_5_3_0_EditorsCanPublishNow.cfc b/modules/contentbox/migrations/2022_08_05_153052_v_5_3_0_EditorsCanPublishNow.cfc index 2fdc6fb803..d970b366a6 100755 --- a/modules/contentbox/migrations/2022_08_05_153052_v_5_3_0_EditorsCanPublishNow.cfc +++ b/modules/contentbox/migrations/2022_08_05_153052_v_5_3_0_EditorsCanPublishNow.cfc @@ -6,33 +6,41 @@ * @author Luis Majano */ component { - // DI property name="migrationService" inject="MigrationService@cfmigrations"; - // Include Utils include template="./util/MigrationUtils.cfm"; - function up( schema, qb ){ + function up( schema, qb ) { // Update permission descriptions - arguments.qb + arguments + .qb .newQuery() .from( "cb_permission" ) .where( "permission", "CONTENTSTORE_EDITOR" ) - .update( { "description" : "Ability to create, edit and publish content store elements" } ); - arguments.qb + .update( + { "description": "Ability to create, edit and publish content store elements" } + ); + arguments + .qb .newQuery() .from( "cb_permission" ) .where( "permission", "ENTRIES_EDITOR" ) - .update( { "description" : "Ability to create, edit and publish blog entries" } ); - arguments.qb + .update( + { "description": "Ability to create, edit and publish blog entries" } + ); + arguments + .qb .newQuery() .from( "cb_permission" ) .where( "permission", "PAGES_EDITOR" ) - .update( { "description" : "Ability to create, edit and publish pages" } ); + .update( + { "description": "Ability to create, edit and publish pages" } + ); } - function down( schema, qb ){ + function down( schema, qb ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/2022_10_13_133204_v_6_0_0_Unique-Site-Slug-Relocation.cfc b/modules/contentbox/migrations/2022_10_13_133204_v_6_0_0_Unique-Site-Slug-Relocation.cfc index 17e4e1d909..eade5e90f4 100755 --- a/modules/contentbox/migrations/2022_10_13_133204_v_6_0_0_Unique-Site-Slug-Relocation.cfc +++ b/modules/contentbox/migrations/2022_10_13_133204_v_6_0_0_Unique-Site-Slug-Relocation.cfc @@ -3,31 +3,37 @@ * https://ortussolutions.atlassian.net/browse/CONTENTBOX-1296 */ component { - // Include Utils include template="./util/MigrationUtils.cfm"; - function up( schema, qb ){ + function up( schema, qb ) { if ( schema.hasTable( "cb_relocations" ) ) { - schema.alter( "cb_relocations", function( table ){ - table.unique( [ "slug", "FK_siteID" ] ); - } ); + schema.alter( + "cb_relocations", + function( table ) { + table.unique( [ "slug", "FK_siteID"] ); + } + ); } else { - arguments.schema.create( "cb_relocations", ( table ) => { - table.string( "relocationID", 36 ).primaryKey(); - table.dateTime( "createdDate" ); - table.dateTime( "modifiedDate" ); - table.boolean( "isDeleted" ).default( false ); - table.string( "slug", 500 ); - table.string( "target", 500 ).nullable(); - table.string( "FK_siteID", 36 ); - table.string( "FK_contentID", 36 ).nullable(); - table.unique( [ "slug", "FK_siteID" ] ); - } ); + arguments.schema.create( + "cb_relocations", + ( table ) => { + table.string( "relocationID", 36 ).primaryKey(); + table.dateTime( "createdDate" ); + table.dateTime( "modifiedDate" ); + table.boolean( "isDeleted" ).default( false ); + table.string( "slug", 500 ); + table.string( "target", 500 ).nullable(); + table.string( "FK_siteID", 36 ); + table.string( "FK_contentID", 36 ).nullable(); + table.unique( [ "slug", "FK_siteID"] ); + } + ); } } - function down( schema, qb ){ + function down( schema, qb ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/2022_10_14_173737_v_6_0_0_Slow-Admin-Search.cfc b/modules/contentbox/migrations/2022_10_14_173737_v_6_0_0_Slow-Admin-Search.cfc index 43c72d801d..e38f4cf878 100755 --- a/modules/contentbox/migrations/2022_10_14_173737_v_6_0_0_Slow-Admin-Search.cfc +++ b/modules/contentbox/migrations/2022_10_14_173737_v_6_0_0_Slow-Admin-Search.cfc @@ -4,13 +4,17 @@ */ component { - function up( schema, qb ){ - schema.alter( "cb_contentVersion", function( table ){ - table.index( [ "isActive", "content" ], "idx_content_isActive" ); - } ); + function up( schema, qb ) { + schema.alter( + "cb_contentVersion", + function( table ) { + table.index( [ "isActive", "content"], "idx_content_isActive" ); + } + ); } - function down( schema, qb ){ + function down( schema, qb ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/2022_11_17_234941_v_6_0_0_SecurityRules-cbsecurity3.cfc b/modules/contentbox/migrations/2022_11_17_234941_v_6_0_0_SecurityRules-cbsecurity3.cfc index a4fc007aa2..ec5ee4fe30 100755 --- a/modules/contentbox/migrations/2022_11_17_234941_v_6_0_0_SecurityRules-cbsecurity3.cfc +++ b/modules/contentbox/migrations/2022_11_17_234941_v_6_0_0_SecurityRules-cbsecurity3.cfc @@ -2,25 +2,31 @@ * Add the new columns for the security rules in cbsecurity 3.x */ component { - // Include Utils include template="./util/MigrationUtils.cfm"; - function up( schema, qb ){ + function up( schema, qb ) { if ( !hasColumn( "cb_securityRule", "httpMethods" ) ) { - schema.alter( "cb_securityRule", ( table ) => { - table.addColumn( table.string( "httpMethods" ).default( "*" ) ); - } ); + schema.alter( + "cb_securityRule", + ( table ) => { + table.addColumn( table.string( "httpMethods" ).default( "*" ) ); + } + ); } if ( !hasColumn( "cb_securityRule", "allowedIPs" ) ) { - schema.alter( "cb_securityRule", ( table ) => { - table.addColumn( table.string( "allowedIPs" ).default( "*" ) ); - } ); + schema.alter( + "cb_securityRule", + ( table ) => { + table.addColumn( table.string( "allowedIPs" ).default( "*" ) ); + } + ); } } - function down( schema, qb ){ + function down( schema, qb ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/2022_11_23_142439_v_6_0_0_Convert-Featured-cbfs.cfc b/modules/contentbox/migrations/2022_11_23_142439_v_6_0_0_Convert-Featured-cbfs.cfc index 6ef1ca47a0..52db94589d 100755 --- a/modules/contentbox/migrations/2022_11_23_142439_v_6_0_0_Convert-Featured-cbfs.cfc +++ b/modules/contentbox/migrations/2022_11_23_142439_v_6_0_0_Convert-Featured-cbfs.cfc @@ -3,16 +3,15 @@ * https://ortussolutions.atlassian.net/browse/CONTENTBOX-1452 */ component { - // Include Utils include template="./util/MigrationUtils.cfm"; - function up( schema, qb ){ + function up( schema, qb ) { var mediaRoot = qb .newQuery() .from( "cb_setting" ) .where( "name", "cb_media_directoryRoot" ) - .where( "isCore", 1 ) + .where( "isCore", qb.getGrammar().convertToBooleanType( true ) ) .first(); if ( !structKeyExists( mediaRoot, "value" ) ) { @@ -22,28 +21,48 @@ component { mediaRoot = mediaRoot.value; - qb.newQuery() + qb + .newQuery() .from( "cb_content" ) - .where( "featuredImage", "!=", "%:%" ) - .select( [ "contentID", "featuredImage" ] ) + .where( + "featuredImage", + "!=", + "%:%" + ) + .select( [ "contentID", "featuredImage"] ) .get() - .each( function( item ){ - if ( findNoCase( mediaRoot, item.featuredImage ) ) { - qb.newQuery() - .from( "cb_content" ) - .where( "contentID", item.contentID ) - .update( { "featuredImage" : replaceNoCase( item.featuredImage, mediaRoot, "contentbox:" ) } ); + .each( + function( item ) { + if ( findNoCase( mediaRoot, item.featuredImage ) ) { + qb + .newQuery() + .from( "cb_content" ) + .where( "contentID", item.contentID ) + .update( + { + "featuredImage": replaceNoCase( + item.featuredImage, + mediaRoot, + "contentbox:" + ) + } + ); + } } - } ); + ); if ( hasColumn( "cb_content", "featuredImageURL" ) ) { - schema.alter( "cb_content", function( table ){ - table.dropColumn( "featuredImageURL" ); - } ); + schema.alter( + "cb_content", + function( table ) { + table.dropColumn( "featuredImageURL" ); + } + ); } } - function down( schema, qb ){ + function down( schema, qb ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/2022_11_23_144748_v_6_0_0_Add-Site-Disk.cfc b/modules/contentbox/migrations/2022_11_23_144748_v_6_0_0_Add-Site-Disk.cfc index 783bc9e40f..69f7e87893 100755 --- a/modules/contentbox/migrations/2022_11_23_144748_v_6_0_0_Add-Site-Disk.cfc +++ b/modules/contentbox/migrations/2022_11_23_144748_v_6_0_0_Add-Site-Disk.cfc @@ -3,19 +3,22 @@ * https://ortussolutions.atlassian.net/browse/CONTENTBOX-1452 */ component { - // Include Utils include template="./util/MigrationUtils.cfm"; - function up( schema, qb ){ + function up( schema, qb ) { if ( !hasColumn( "cb_site", "mediaDisk" ) ) { - schema.alter( "cb_site", function( table ){ - table.addColumn( table.string( "mediaDisk", 50 ).nullable() ); - } ); + schema.alter( + "cb_site", + function( table ) { + table.addColumn( table.string( "mediaDisk", 50 ).nullable() ); + } + ); } } - function down( schema, qb ){ + function down( schema, qb ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/2023_07_13_092814_v_6_0_0_ContentTemplates.cfc b/modules/contentbox/migrations/2023_07_13_092814_v_6_0_0_ContentTemplates.cfc index d892fa6bde..52dbe17028 100755 --- a/modules/contentbox/migrations/2023_07_13_092814_v_6_0_0_ContentTemplates.cfc +++ b/modules/contentbox/migrations/2023_07_13_092814_v_6_0_0_ContentTemplates.cfc @@ -3,71 +3,86 @@ * https://ortussolutions.atlassian.net/browse/CONTENTBOX-1270 */ component { - // Include Utils include template="./util/MigrationUtils.cfm"; - function up( schema, qb ){ + function up( schema, qb ) { // Content Templates if ( !schema.hasTable( "cb_contentTemplate" ) ) { - arguments.schema.create( "cb_contentTemplate", ( table ) => { - // Columns - table.string( "templateID", 36 ).primaryKey(); - table.dateTime( "createdDate" ); - table.dateTime( "modifiedDate" ); - table.boolean( "isDeleted" ).default( false ); - table.boolean( "isGlobal" ).default( false ); - table.string( "contentType", 50 ); - table.string( "name", 255 ); - table.string( "description", 1000 ); - table.longText( "definition" ); + arguments.schema.create( + "cb_contentTemplate", + ( table ) => { + table.string( "templateID", 36 ).primaryKey(); + table.dateTime( "createdDate" ); + table.dateTime( "modifiedDate" ); + table.boolean( "isDeleted" ).default( false ); + table.boolean( "isGlobal" ).default( false ); + table.string( "contentType", 50 ); + table.string( "name", 255 ); + table.string( "description", 1000 ); + table.longText( "definition" ); - // Relationships - table.string( "FK_authorID", 36 ); - table.string( "FK_siteID", 36 ).nullable(); - table - .foreignKey( "FK_authorID" ) - .references( "authorID" ) - .onTable( "cb_author" ); - table - .foreignKey( "FK_siteID" ) - .references( "siteID" ) - .onTable( "cb_site" ); + table.string( "FK_authorID", 36 ); + table.string( "FK_siteID", 36 ).nullable(); + table + .foreignKey( "FK_authorID" ) + .references( "authorID" ) + .onTable( "cb_author" ); + table + .foreignKey( "FK_siteID" ) + .references( "siteID" ) + .onTable( "cb_site" ); - // Indexes - table.index( [ "contentType" ], "idx_contentType" ); - } ); + table.index( [ "contentType"], "idx_contentType" ); + } + ); } else { - systemOutput( "- skipping 'cb_contentTemplate' creation, table already there", true ); + systemOutput( + "- skipping 'cb_contentTemplate' creation, table already there", + true + ); } // Relationship between Content Templates and Content if ( !hasColumn( "cb_content", "FK_contentTemplateID" ) ) { - schema.alter( "cb_content", ( table ) => { - table.addColumn( table.string( "FK_contentTemplateID", 36 ).nullable() ); - table - .foreignKey( "FK_contentTemplateID" ) - .references( "templateID" ) - .onTable( "cb_contentTemplate" ); - } ); + schema.alter( + "cb_content", + ( table ) => { + table.addColumn( table.string( "FK_contentTemplateID", 36 ).nullable() ); + table + .foreignKey( "FK_contentTemplateID" ) + .references( "templateID" ) + .onTable( "cb_contentTemplate" ); + } + ); } else { - systemOutput( "- skipping 'cb_content.FK_contentTemplateID' creation, column already there", true ); + systemOutput( + "- skipping 'cb_content.FK_contentTemplateID' creation, column already there", + true + ); } if ( !hasColumn( "cb_content", "FK_childContentTemplateID" ) ) { - schema.alter( "cb_content", ( table ) => { - table.addColumn( table.string( "FK_childContentTemplateID", 36 ).nullable() ); - table - .foreignKey( "FK_childContentTemplateID" ) - .references( "templateID" ) - .onTable( "cb_contentTemplate" ); - } ); + schema.alter( + "cb_content", + ( table ) => { + table.addColumn( table.string( "FK_childContentTemplateID", 36 ).nullable() ); + table + .foreignKey( "FK_childContentTemplateID" ) + .references( "templateID" ) + .onTable( "cb_contentTemplate" ); + } + ); } else { - systemOutput( "- skipping 'cb_content.FK_childContentTemplateID' creation, column already there", true ); + systemOutput( + "- skipping 'cb_content.FK_childContentTemplateID' creation, column already there", + true + ); } } - function down( schema, qb ){ + function down( schema, qb ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/2023_10_18_173527_v_6_0_0_SiteDomainAliases.cfc b/modules/contentbox/migrations/2023_10_18_173527_v_6_0_0_SiteDomainAliases.cfc index 524c80f51f..c171676e43 100755 --- a/modules/contentbox/migrations/2023_10_18_173527_v_6_0_0_SiteDomainAliases.cfc +++ b/modules/contentbox/migrations/2023_10_18_173527_v_6_0_0_SiteDomainAliases.cfc @@ -2,20 +2,23 @@ * Sites can now have domain aliases for matching on the request */ component { - // Include Utils include template="./util/MigrationUtils.cfm"; - function up( schema, qb ){ + function up( schema, qb ) { if ( !hasColumn( "cb_site", "domainAliases" ) ) { - schema.alter( "cb_site", function( table ){ - table.addColumn( table.text( "domainAliases" ).nullable() ); - } ); + schema.alter( + "cb_site", + function( table ) { + table.addColumn( table.text( "domainAliases" ).nullable() ); + } + ); queryExecute( "update cb_site set domainAliases = '[]'" ); } } - function down( schema, qb ){ + function down( schema, qb ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/2023_12_12_164002_EditorsCanClearCaches.cfc b/modules/contentbox/migrations/2023_12_12_164002_EditorsCanClearCaches.cfc index db50390d67..0753ffe352 100755 --- a/modules/contentbox/migrations/2023_12_12_164002_EditorsCanClearCaches.cfc +++ b/modules/contentbox/migrations/2023_12_12_164002_EditorsCanClearCaches.cfc @@ -6,40 +6,41 @@ * @author Luis Majano */ component { - // DI property name="migrationService" inject="MigrationService@cfmigrations"; - // Include Utils include template="./util/MigrationUtils.cfm"; - function up( schema, qb ){ - var today = now(); + function up( schema, qb ) { + var today = now(); var permID = createUUID(); if ( - !qb.newQuery() + !qb + .newQuery() .from( "cb_permission" ) .where( "permission", "RELOAD_CACHES" ) .count() ) { - qb.newQuery() + qb + .newQuery() .from( "cb_permission" ) - .insert( { - "permissionID" : permID, - "createdDate" : today, - "modifiedDate" : today, - "isDeleted" : 0, - "permission" : "RELOAD_CACHES", - "description" : "Ability to reload caches" - } ); + .insert( + { + "permissionID": permID, + "createdDate" : today, + "modifiedDate": today, + "isDeleted" : 0, + "permission" : "RELOAD_CACHES", + "description" : "Ability to reload caches" + } + ); systemOutput( "√ - Reload Caches permission created", true ); } else { var permId = qb .newQuery() .from( "cb_permission" ) .where( "permission", "RELOAD_CACHES" ) - .first() - .permissionID; + .first().permissionID; } // Assign to Editors and Administrators @@ -51,15 +52,17 @@ component { .first(); if ( - !qb.newQuery() + !qb + .newQuery() .from( "cb_rolePermissions" ) .where( "FK_permissionID", permID ) .where( "FK_roleID", admin.roleID ) .count() ) { - qb.newQuery() + qb + .newQuery() .from( "cb_rolePermissions" ) - .insert( { "FK_roleID" : admin.roleID, "FK_permissionID" : permID } ); + .insert( { "FK_roleID": admin.roleID, "FK_permissionID": permID } ); systemOutput( "√ - Admin role updated with new permissions", true ); } @@ -71,20 +74,23 @@ component { .first(); if ( - !qb.newQuery() + !qb + .newQuery() .from( "cb_rolePermissions" ) .where( "FK_permissionID", permID ) .where( "FK_roleID", editor.roleID ) .count() ) { - qb.newQuery() + qb + .newQuery() .from( "cb_rolePermissions" ) - .insert( { "FK_roleID" : editor.roleID, "FK_permissionID" : permID } ); + .insert( { "FK_roleID": editor.roleID, "FK_permissionID": permID } ); systemOutput( "√ - Editor role updated with new permissions", true ); } } - function down( schema, qb ){ + function down( schema, qb ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/2026_05_19_210955_performance_updates.cfc b/modules/contentbox/migrations/2026_05_19_210955_performance_updates.cfc new file mode 100755 index 0000000000..0b3a97ad8e --- /dev/null +++ b/modules/contentbox/migrations/2026_05_19_210955_performance_updates.cfc @@ -0,0 +1,46 @@ +component { + + function up( schema, qb ) { + schema.alter( + "cb_content", + ( table ) => { + table.index( + [ "isPublished", "contentType", "passwordProtection", "FK_siteID", "publishedDate"], + "idx_content_published_search" + ); + } + ); + + schema.alter( + "cb_contentCategories", + ( table ) => { + table.index( + [ "FK_categoryID", "FK_contentID"], + "idx_category_content" + ); + table.index( + [ "FK_contentID", "FK_categoryID"], + "idx_content_category" + ); + } + ); + } + + function down( schema, qb ) { + schema.alter( + "cb_contentCategories", + ( table ) => { + table.dropIndex( "idx_content_category" ); + table.dropIndex( "idx_category_content" ); + } + ); + + schema.alter( + "cb_content", + ( table ) => { + table.dropIndex( "idx_content_published_search" ); + } + ); + } + +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_author.cfc b/modules/contentbox/migrations/init/create_author.cfc index db8bba004b..97c20f087f 100755 --- a/modules/contentbox/migrations/init/create_author.cfc +++ b/modules/contentbox/migrations/init/create_author.cfc @@ -1,40 +1,40 @@ component { - function up( schema, query ){ - schema.create( "cb_author", ( table ) => { - // Base Columns - table.string( "authorID", 36 ).primaryKey(); - table.datetime( "createdDate" ).withCurrent(); - table.datetime( "modifiedDate" ).withCurrent(); - table.boolean( "isDeleted" ).default( false ); + function up( schema, query ) { + schema.create( + "cb_author", + ( table ) => { + table.string( "authorID", 36 ).primaryKey(); + table.datetime( "createdDate" ).withCurrent(); + table.datetime( "modifiedDate" ).withCurrent(); + table.boolean( "isDeleted" ).default( false ); - table.string( "firstName", 100 ); - table.string( "lastName", 100 ); - table.string( "email" ); - table.string( "username" ).unique(); - table.string( "password" ); - table.boolean( "isActive" ).default( true ); - table.datetime( "lastLogin" ).nullable(); - table.longText( "biography" ).nullable(); - table.longText( "preferences" ).nullable(); - table.boolean( "isPasswordReset" ).default( false ); - table.boolean( "is2FactorAuth" ).default( false ); + table.string( "firstName", 100 ); + table.string( "lastName", 100 ); + table.string( "email" ); + table.string( "username" ).unique(); + table.string( "password" ); + table.boolean( "isActive" ).default( true ); + table.datetime( "lastLogin" ).nullable(); + table.longText( "biography" ).nullable(); + table.longText( "preferences" ).nullable(); + table.boolean( "isPasswordReset" ).default( false ); + table.boolean( "is2FactorAuth" ).default( false ); - // Relationships - table.string( "FK_roleID", 36 ); - table - .foreignKey( "FK_roleID" ) - .references( "roleID" ) - .onTable( "cb_role" ); + table.string( "FK_roleID", 36 ); + table + .foreignKey( "FK_roleID" ) + .references( "roleID" ) + .onTable( "cb_role" ); - // Indexes - table.index( [ "email" ], "idx_email" ); - table.index( [ "isDeleted" ], "idx_author_deleted" ); - table.index( [ "isActive" ], "idx_activeAuthor" ); - table.index( [ "isPasswordReset" ], "idx_passwordReset" ); - table.index( [ "is2FactorAuth" ], "idx_2factorauth" ); - table.index( [ "username", "password", "isActive" ], "idx_login" ); - } ); + table.index( [ "email"], "idx_email" ); + table.index( [ "isDeleted"], "idx_author_deleted" ); + table.index( [ "isActive"], "idx_activeAuthor" ); + table.index( [ "isPasswordReset"], "idx_passwordReset" ); + table.index( [ "is2FactorAuth"], "idx_2factorauth" ); + table.index( [ "username", "password", "isActive"], "idx_login" ); + } + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_author_permission_groups.cfc b/modules/contentbox/migrations/init/create_author_permission_groups.cfc index 63f48be61a..eae775e861 100644 --- a/modules/contentbox/migrations/init/create_author_permission_groups.cfc +++ b/modules/contentbox/migrations/init/create_author_permission_groups.cfc @@ -1,22 +1,26 @@ component { - function up( schema, query ){ - schema.create( "cb_authorPermissionGroups", function( table ){ - table.string( "FK_permissionGroupID", 36 ); - table.string( "FK_authorID", 36 ); + function up( schema, query ) { + schema.create( + "cb_authorPermissionGroups", + function( table ) { + table.string( "FK_permissionGroupID", 36 ); + table.string( "FK_authorID", 36 ); - table - .foreignKey( "FK_permissionGroupID" ) - .references( "permissionGroupID" ) - .onTable( "cb_permissionGroup" ); - table - .foreignKey( "FK_authorID" ) - .references( "authorID" ) - .onTable( "cb_author" ); - } ); + table + .foreignKey( "FK_permissionGroupID" ) + .references( "permissionGroupID" ) + .onTable( "cb_permissionGroup" ); + table + .foreignKey( "FK_authorID" ) + .references( "authorID" ) + .onTable( "cb_author" ); + } + ); } - function down( schema, query ){ + function down( schema, query ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_author_permissions.cfc b/modules/contentbox/migrations/init/create_author_permissions.cfc index 7244c79072..97ed6d65c3 100644 --- a/modules/contentbox/migrations/init/create_author_permissions.cfc +++ b/modules/contentbox/migrations/init/create_author_permissions.cfc @@ -1,22 +1,26 @@ component { - function up( schema, query ){ - schema.create( "cb_authorPermissions", function( table ){ - table.string( "FK_permissionID", 36 ); - table.string( "FK_authorID", 36 ); + function up( schema, query ) { + schema.create( + "cb_authorPermissions", + function( table ) { + table.string( "FK_permissionID", 36 ); + table.string( "FK_authorID", 36 ); - table - .foreignKey( "FK_permissionID" ) - .references( "permissionID" ) - .onTable( "cb_permission" ); - table - .foreignKey( "FK_authorID" ) - .references( "authorID" ) - .onTable( "cb_author" ); - } ); + table + .foreignKey( "FK_permissionID" ) + .references( "permissionID" ) + .onTable( "cb_permission" ); + table + .foreignKey( "FK_authorID" ) + .references( "authorID" ) + .onTable( "cb_author" ); + } + ); } - function down( schema, query ){ + function down( schema, query ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_category.cfc b/modules/contentbox/migrations/init/create_category.cfc index aaf91d7c6c..de06c7310d 100755 --- a/modules/contentbox/migrations/init/create_category.cfc +++ b/modules/contentbox/migrations/init/create_category.cfc @@ -1,33 +1,34 @@ component { - function up( schema, query ){ - schema.create( "cb_category", function( table ){ - // Base Columns - table.string( "categoryID", 36 ).primaryKey(); - table.datetime( "createdDate" ).withCurrent(); - table.datetime( "modifiedDate" ).withCurrent(); - table.boolean( "isDeleted" ).default( false ); + function up( schema, query ) { + schema.create( + "cb_category", + function( table ) { + table.string( "categoryID", 36 ).primaryKey(); + table.datetime( "createdDate" ).withCurrent(); + table.datetime( "modifiedDate" ).withCurrent(); + table.boolean( "isDeleted" ).default( false ); - table.string( "slug" ); - table.string( "category" ); - table.boolean( "isPublic" ).default( true ); + table.string( "slug" ); + table.string( "category" ); + table.boolean( "isPublic" ).default( true ); - // Relationships - table.string( "FK_siteID", 36 ); - table - .foreignKey( "FK_siteID" ) - .references( "siteID" ) - .onTable( "cb_site" ); + table.string( "FK_siteID", 36 ); + table + .foreignKey( "FK_siteID" ) + .references( "siteID" ) + .onTable( "cb_site" ); - // Index - table.index( [ "isPublic" ], "idx_isPublic" ); - table.index( [ "slug" ], "idx_categorySlug" ); - table.index( [ "category" ], "idx_categoryName" ); - table.index( [ "isDeleted" ], "idx_category_deleted" ); - } ); + table.index( [ "isPublic"], "idx_isPublic" ); + table.index( [ "slug"], "idx_categorySlug" ); + table.index( [ "category"], "idx_categoryName" ); + table.index( [ "isDeleted"], "idx_category_deleted" ); + } + ); } - function down( schema, query ){ + function down( schema, query ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_comment_subscriptions.cfc b/modules/contentbox/migrations/init/create_comment_subscriptions.cfc index 8b58d74d90..6e6c529ccc 100644 --- a/modules/contentbox/migrations/init/create_comment_subscriptions.cfc +++ b/modules/contentbox/migrations/init/create_comment_subscriptions.cfc @@ -1,22 +1,26 @@ component { - function up( schema, query ){ - schema.create( "cb_commentSubscriptions", function( table ){ - table.string( "subscriptionID", 36 ); - table.string( "FK_contentID", 36 ); + function up( schema, query ) { + schema.create( + "cb_commentSubscriptions", + function( table ) { + table.string( "subscriptionID", 36 ); + table.string( "FK_contentID", 36 ); - table - .foreignKey( "subscriptionID" ) - .references( "subscriptionID" ) - .onTable( "cb_subscriptions" ); - table - .foreignKey( "FK_contentID" ) - .references( "contentID" ) - .onTable( "cb_content" ); - } ); + table + .foreignKey( "subscriptionID" ) + .references( "subscriptionID" ) + .onTable( "cb_subscriptions" ); + table + .foreignKey( "FK_contentID" ) + .references( "contentID" ) + .onTable( "cb_content" ); + } + ); } - function down( schema, query ){ + function down( schema, query ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_comments.cfc b/modules/contentbox/migrations/init/create_comments.cfc index b13b90c9e6..4a461e37ae 100755 --- a/modules/contentbox/migrations/init/create_comments.cfc +++ b/modules/contentbox/migrations/init/create_comments.cfc @@ -1,32 +1,32 @@ component { - function up( schema, query ){ - schema.create( "cb_comment", ( table ) => { - // Base Columns - table.string( "commentID", 36 ).primaryKey(); - table.datetime( "createdDate" ).withCurrent(); - table.datetime( "modifiedDate" ).withCurrent(); - table.boolean( "isDeleted" ).default( false ); + function up( schema, query ) { + schema.create( + "cb_comment", + ( table ) => { + table.string( "commentID", 36 ).primaryKey(); + table.datetime( "createdDate" ).withCurrent(); + table.datetime( "modifiedDate" ).withCurrent(); + table.boolean( "isDeleted" ).default( false ); - table.longText( "content" ); - table.string( "author", 100 ); - table.string( "authorIP", 100 ); - table.string( "authorEmail" ); - table.string( "authorURL" ).nullable(); - table.boolean( "isApproved" ).default( false ); + table.longText( "content" ); + table.string( "author", 100 ); + table.string( "authorIP", 100 ); + table.string( "authorEmail" ); + table.string( "authorURL" ).nullable(); + table.boolean( "isApproved" ).default( false ); - // Relationships - table.string( "FK_contentID", 36 ); - table - .foreignKey( "FK_contentID" ) - .references( "contentID" ) - .onTable( "cb_content" ); + table.string( "FK_contentID", 36 ); + table + .foreignKey( "FK_contentID" ) + .references( "contentID" ) + .onTable( "cb_content" ); - // Indexes - table.index( [ "isApproved", "FK_contentID" ], "idx_contentComment" ); - table.index( [ "isApproved" ], "idx_approved" ); - table.index( [ "isDeleted" ], "idx_comments_deleted" ); - } ); + table.index( [ "isApproved", "FK_contentID"], "idx_contentComment" ); + table.index( [ "isApproved"], "idx_approved" ); + table.index( [ "isDeleted"], "idx_comments_deleted" ); + } + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_content.cfc b/modules/contentbox/migrations/init/create_content.cfc index 23a6537831..9f3263fdc8 100644 --- a/modules/contentbox/migrations/init/create_content.cfc +++ b/modules/contentbox/migrations/init/create_content.cfc @@ -1,64 +1,65 @@ component { - function up( schema, query ){ - schema.create( "cb_content", function( table ){ - // Base Columns - table.string( "contentID", 36 ).primaryKey(); - table.datetime( "createdDate" ).withCurrent(); - table.datetime( "modifiedDate" ).withCurrent(); - table.boolean( "isDeleted" ).default( false ); - // Content Columns - table.string( "contentType" ); - table.string( "title", 500 ); - table.string( "slug" ); - table.datetime( "publishedDate" ).nullable(); - table.datetime( "expireDate" ).nullable(); - table.boolean( "isPublished" ).default( true ); - table.boolean( "allowComments" ).default( true ); - table.string( "passwordProtection", 100 ).nullable(); - table.string( "HTMLKeywords", 160 ).nullable(); - table.string( "HTMLDescription", 160 ).nullable(); - table.string( "HTMLTitle" ).nullable(); - table.boolean( "cache" ).default( true ); - table.integer( "cacheTimeout" ).default( 0 ); - table.integer( "cacheLastAccessTimeout" ).default( 0 ); - table.string( "markup", 100 ).default( "HTML" ); - table.boolean( "showInSearch" ).default( true ); - table.string( "featuredImage", 500 ).nullable(); + function up( schema, query ) { + schema.create( + "cb_content", + function( table ) { + table.string( "contentID", 36 ).primaryKey(); + table.datetime( "createdDate" ).withCurrent(); + table.datetime( "modifiedDate" ).withCurrent(); + table.boolean( "isDeleted" ).default( false ); - // Relationships - table.string( "FK_siteID", 36 ); - table - .foreignKey( "FK_siteID" ) - .references( "siteID" ) - .onTable( "cb_site" ); - table.string( "FK_authorID", 36 ); - table - .foreignKey( "FK_authorID" ) - .references( "authorID" ) - .onTable( "cb_author" ); - table.string( "FK_parentID", 36 ).nullable(); - table - .foreignKey( "FK_parentID" ) - .references( "contentID" ) - .onTable( "cb_content" ); + table.string( "contentType" ); + table.string( "title", 500 ); + table.string( "slug" ); + table.datetime( "publishedDate" ).nullable(); + table.datetime( "expireDate" ).nullable(); + table.boolean( "isPublished" ).default( true ); + table.boolean( "allowComments" ).default( true ); + table.string( "passwordProtection", 100 ).nullable(); + table.string( "HTMLKeywords", 160 ).nullable(); + table.string( "HTMLDescription", 160 ).nullable(); + table.string( "HTMLTitle" ).nullable(); + table.boolean( "cache" ).default( true ); + table.integer( "cacheTimeout" ).default( 0 ); + table.integer( "cacheLastAccessTimeout" ).default( 0 ); + table.string( "markup", 100 ).default( "HTML" ); + table.boolean( "showInSearch" ).default( true ); + table.string( "featuredImage", 500 ).nullable(); - // Index - table.index( [ "contentType" ], "idx_discriminator" ); - table.index( [ "isPublished", "contentType" ], "idx_published" ); - table.index( [ "slug" ], "idx_slug" ); - table.index( [ "slug", "isPublished" ], "idx_publishedSlug" ); - table.index( [ "publishedDate" ], "idx_publishedDate" ); - table.index( [ "expireDate" ], "idx_expireDate" ); - table.index( [ "title", "isPublished" ], "idx_search" ); - table.index( [ "cache" ], "idx_cache" ); - table.index( [ "cacheTimeout" ], "idx_cachetimeout" ); - table.index( [ "cacheLastAccessTimeout" ], "idx_cachelastaccesstimeout" ); - table.index( [ "showInSearch" ], "idx_showInSearch" ); - } ); + table.string( "FK_siteID", 36 ); + table + .foreignKey( "FK_siteID" ) + .references( "siteID" ) + .onTable( "cb_site" ); + table.string( "FK_authorID", 36 ); + table + .foreignKey( "FK_authorID" ) + .references( "authorID" ) + .onTable( "cb_author" ); + table.string( "FK_parentID", 36 ).nullable(); + table + .foreignKey( "FK_parentID" ) + .references( "contentID" ) + .onTable( "cb_content" ); + + table.index( [ "contentType"], "idx_discriminator" ); + table.index( [ "isPublished", "contentType"], "idx_published" ); + table.index( [ "slug"], "idx_slug" ); + table.index( [ "slug", "isPublished"], "idx_publishedSlug" ); + table.index( [ "publishedDate"], "idx_publishedDate" ); + table.index( [ "expireDate"], "idx_expireDate" ); + table.index( [ "title", "isPublished"], "idx_search" ); + table.index( [ "cache"], "idx_cache" ); + table.index( [ "cacheTimeout"], "idx_cachetimeout" ); + table.index( [ "cacheLastAccessTimeout"], "idx_cachelastaccesstimeout" ); + table.index( [ "showInSearch"], "idx_showInSearch" ); + } + ); } - function down( schema, query ){ + function down( schema, query ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_contentStore.cfc b/modules/contentbox/migrations/init/create_contentStore.cfc index a0f1dca260..eb05586565 100644 --- a/modules/contentbox/migrations/init/create_contentStore.cfc +++ b/modules/contentbox/migrations/init/create_contentStore.cfc @@ -1,23 +1,26 @@ component { - function up( schema, query ){ - schema.create( "cb_contentStore", function( table ){ - table.string( "contentID", 36 ).primaryKey(); - table - .integer( "order" ) - .default( 0 ) - .nullable(); - table.string( "description", 500 ).nullable(); + function up( schema, query ) { + schema.create( + "cb_contentStore", + function( table ) { + table.string( "contentID", 36 ).primaryKey(); + table + .integer( "order" ) + .default( 0 ) + .nullable(); + table.string( "description", 500 ).nullable(); - // Relationships - table - .foreignKey( "contentID" ) - .references( "contentID" ) - .onTable( "cb_content" ); - } ); + table + .foreignKey( "contentID" ) + .references( "contentID" ) + .onTable( "cb_content" ); + } + ); } - function down( schema, query ){ + function down( schema, query ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_content_categories.cfc b/modules/contentbox/migrations/init/create_content_categories.cfc index 1f788b5191..2c7b99927f 100644 --- a/modules/contentbox/migrations/init/create_content_categories.cfc +++ b/modules/contentbox/migrations/init/create_content_categories.cfc @@ -1,22 +1,26 @@ component { - function up( schema, query ){ - schema.create( "cb_contentCategories", function( table ){ - table.string( "FK_contentID", 36 ); - table.string( "FK_categoryID", 36 ); + function up( schema, query ) { + schema.create( + "cb_contentCategories", + function( table ) { + table.string( "FK_contentID", 36 ); + table.string( "FK_categoryID", 36 ); - table - .foreignKey( "FK_contentID" ) - .references( "contentID" ) - .onTable( "cb_content" ); - table - .foreignKey( "FK_categoryID" ) - .references( "categoryID" ) - .onTable( "cb_category" ); - } ); + table + .foreignKey( "FK_contentID" ) + .references( "contentID" ) + .onTable( "cb_content" ); + table + .foreignKey( "FK_categoryID" ) + .references( "categoryID" ) + .onTable( "cb_category" ); + } + ); } - function down( schema, query ){ + function down( schema, query ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_content_templates.cfc b/modules/contentbox/migrations/init/create_content_templates.cfc index 6e53e12038..dd25e88091 100644 --- a/modules/contentbox/migrations/init/create_content_templates.cfc +++ b/modules/contentbox/migrations/init/create_content_templates.cfc @@ -4,55 +4,62 @@ */ component { - function up( schema, qb ){ - schema.create( "cb_contentTemplate", ( table ) => { - // Base Columns - table.string( "templateID", 36 ).primaryKey(); - table.datetime( "createdDate" ).withCurrent(); - table.datetime( "modifiedDate" ).withCurrent(); - table.boolean( "isDeleted" ).default( false ); - - table.boolean( "isGlobal" ).default( false ); - table.string( "contentType", 50 ).nullable(); - table.string( "name", 255 ); - table.string( "description", 1000 ).nullable(); - table.longText( "definition" ); - - // Relationships - table.string( "FK_authorID", 36 ); - table - .foreignKey( "FK_authorID" ) - .references( "authorID" ) - .onTable( "cb_author" ); - table.string( "FK_siteID", 36 ); - table - .foreignKey( "FK_siteID" ) - .references( "siteID" ) - .onTable( "cb_site" ); - - // Indexes - table.index( [ "contentType" ], "idx_contentType" ); - } ); + function up( schema, qb ) { + schema.create( + "cb_contentTemplate", + ( table ) => { + table.string( "templateID", 36 ).primaryKey(); + table.datetime( "createdDate" ).withCurrent(); + table.datetime( "modifiedDate" ).withCurrent(); + table.boolean( "isDeleted" ).default( false ); + + table.boolean( "isGlobal" ).default( false ); + table.string( "contentType", 50 ).nullable(); + table.string( "name", 255 ); + table.string( "description", 1000 ).nullable(); + table.longText( "definition" ); + + table.string( "FK_authorID", 36 ); + table + .foreignKey( "FK_authorID" ) + .references( "authorID" ) + .onTable( "cb_author" ); + table.string( "FK_siteID", 36 ); + table + .foreignKey( "FK_siteID" ) + .references( "siteID" ) + .onTable( "cb_site" ); + + table.index( [ "contentType"], "idx_contentType" ); + } + ); // Relationship between Content Templates and Content - schema.alter( "cb_content", ( table ) => { - table.addColumn( table.string( "FK_contentTemplateID", 36 ).nullable() ); - table - .foreignKey( "FK_contentTemplateID" ) - .references( "templateID" ) - .onTable( "cb_contentTemplate" ); - } ); - - schema.alter( "cb_content", ( table ) => { - table.addColumn( table.string( "FK_childContentTemplateID", 36 ).nullable() ); - table - .foreignKey( "FK_childContentTemplateID" ) - .references( "templateID" ) - .onTable( "cb_contentTemplate" ); - } ); + schema.alter( + "cb_content", + ( table ) => { + table.addColumn( table.string( "FK_contentTemplateID", 36 ).nullable() ); + table + .foreignKey( "FK_contentTemplateID" ) + .references( "templateID" ) + .onTable( "cb_contentTemplate" ); + } + ); + + schema.alter( + "cb_content", + ( table ) => { + table.addColumn( table.string( "FK_childContentTemplateID", 36 ).nullable() ); + table + .foreignKey( "FK_childContentTemplateID" ) + .references( "templateID" ) + .onTable( "cb_contentTemplate" ); + } + ); } - function down( schema, qb ){ + function down( schema, qb ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_content_versions.cfc b/modules/contentbox/migrations/init/create_content_versions.cfc index b5089c778c..b28d4d94f7 100644 --- a/modules/contentbox/migrations/init/create_content_versions.cfc +++ b/modules/contentbox/migrations/init/create_content_versions.cfc @@ -1,39 +1,40 @@ component { - function up( schema, query ){ - schema.create( "cb_contentVersion", function( table ){ - // Base Columns - table.string( "contentVersionID", 36 ).primaryKey(); - table.datetime( "createdDate" ).withCurrent(); - table.datetime( "modifiedDate" ).withCurrent(); - table.boolean( "isDeleted" ).default( false ); - // Content Version Columns - table.longText( "content" ); - table.longText( "changelog" ).nullable(); - table.integer( "version" ).default( 1 ); - table.boolean( "isActive" ).default( true ); + function up( schema, query ) { + schema.create( + "cb_contentVersion", + function( table ) { + table.string( "contentVersionID", 36 ).primaryKey(); + table.datetime( "createdDate" ).withCurrent(); + table.datetime( "modifiedDate" ).withCurrent(); + table.boolean( "isDeleted" ).default( false ); - // Relationships - table.string( "FK_authorID", 36 ); - table - .foreignKey( "FK_authorID" ) - .references( "authorID" ) - .onTable( "cb_author" ); - table.string( "FK_contentID", 36 ); - table - .foreignKey( "FK_contentID" ) - .references( "contentID" ) - .onTable( "cb_content" ); + table.longText( "content" ); + table.longText( "changelog" ).nullable(); + table.integer( "version" ).default( 1 ); + table.boolean( "isActive" ).default( true ); - // Index - table.index( [ "version" ], "idx_version" ); - table.index( [ "isActive" ], "idx_activeContentVersion" ); - table.index( [ "FK_contentID", "isActive" ], "idx_contentVersions" ); - table.index( [ "isActive" ], "idx_content_isActive" ); - } ); + table.string( "FK_authorID", 36 ); + table + .foreignKey( "FK_authorID" ) + .references( "authorID" ) + .onTable( "cb_author" ); + table.string( "FK_contentID", 36 ); + table + .foreignKey( "FK_contentID" ) + .references( "contentID" ) + .onTable( "cb_content" ); + + table.index( [ "version"], "idx_version" ); + table.index( [ "isActive"], "idx_activeContentVersion" ); + table.index( [ "FK_contentID", "isActive"], "idx_contentVersions" ); + table.index( [ "isActive"], "idx_content_isActive" ); + } + ); } - function down( schema, query ){ + function down( schema, query ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_custom_fields.cfc b/modules/contentbox/migrations/init/create_custom_fields.cfc index 6e4a2ebb05..eb904c3c16 100644 --- a/modules/contentbox/migrations/init/create_custom_fields.cfc +++ b/modules/contentbox/migrations/init/create_custom_fields.cfc @@ -1,23 +1,24 @@ component { - function up( schema, query ){ - schema.create( "cb_customfield", ( table ) => { - // Base Columns - table.string( "customFieldID", 36 ).primaryKey(); - table.datetime( "createdDate" ).withCurrent(); - table.datetime( "modifiedDate" ).withCurrent(); - table.boolean( "isDeleted" ).default( false ); + function up( schema, query ) { + schema.create( + "cb_customfield", + ( table ) => { + table.string( "customFieldID", 36 ).primaryKey(); + table.datetime( "createdDate" ).withCurrent(); + table.datetime( "modifiedDate" ).withCurrent(); + table.boolean( "isDeleted" ).default( false ); - table.string( "key" ); - table.longText( "value" ); + table.string( "key" ); + table.longText( "value" ); - // Relationships - table.string( "FK_contentID", 36 ); - table - .foreignKey( "FK_contentID" ) - .references( "contentID" ) - .onTable( "cb_content" ); - } ); + table.string( "FK_contentID", 36 ); + table + .foreignKey( "FK_contentID" ) + .references( "contentID" ) + .onTable( "cb_content" ); + } + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_entry.cfc b/modules/contentbox/migrations/init/create_entry.cfc index b397f8b49f..0884da09e6 100644 --- a/modules/contentbox/migrations/init/create_entry.cfc +++ b/modules/contentbox/migrations/init/create_entry.cfc @@ -1,19 +1,22 @@ component { - function up( schema, query ){ - schema.create( "cb_entry", function( table ){ - table.string( "contentID", 36 ).primaryKey(); - table.longtext( "excerpt" ).nullable(); + function up( schema, query ) { + schema.create( + "cb_entry", + function( table ) { + table.string( "contentID", 36 ).primaryKey(); + table.longtext( "excerpt" ).nullable(); - // Relationships - table - .foreignKey( "contentID" ) - .references( "contentID" ) - .onTable( "cb_content" ); - } ); + table + .foreignKey( "contentID" ) + .references( "contentID" ) + .onTable( "cb_content" ); + } + ); } - function down( schema, query ){ + function down( schema, query ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_group_permissions.cfc b/modules/contentbox/migrations/init/create_group_permissions.cfc index 82489a6b83..24bd48a3a6 100644 --- a/modules/contentbox/migrations/init/create_group_permissions.cfc +++ b/modules/contentbox/migrations/init/create_group_permissions.cfc @@ -1,22 +1,26 @@ component { - function up( schema, query ){ - schema.create( "cb_groupPermissions", function( table ){ - table.string( "FK_permissionGroupID", 36 ); - table.string( "FK_permissionID", 36 ); + function up( schema, query ) { + schema.create( + "cb_groupPermissions", + function( table ) { + table.string( "FK_permissionGroupID", 36 ); + table.string( "FK_permissionID", 36 ); - table - .foreignKey( "FK_permissionGroupID" ) - .references( "permissionGroupID" ) - .onTable( "cb_permissionGroup" ); - table - .foreignKey( "FK_permissionID" ) - .references( "permissionID" ) - .onTable( "cb_permission" ); - } ); + table + .foreignKey( "FK_permissionGroupID" ) + .references( "permissionGroupID" ) + .onTable( "cb_permissionGroup" ); + table + .foreignKey( "FK_permissionID" ) + .references( "permissionID" ) + .onTable( "cb_permission" ); + } + ); } - function down( schema, query ){ + function down( schema, query ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_jwt.cfc b/modules/contentbox/migrations/init/create_jwt.cfc index 985c2fbe44..61b7931c05 100644 --- a/modules/contentbox/migrations/init/create_jwt.cfc +++ b/modules/contentbox/migrations/init/create_jwt.cfc @@ -1,18 +1,19 @@ component { - function up( schema, query ){ - schema.create( "cb_jwt", ( table ) => { - // Base Columns - table.string( "id", 36 ).primaryKey(); - table.datetime( "expiration" ); - table.datetime( "issued" ); - table.longtext( "token" ); - table.string( "cacheKey" ); - table.string( "subject" ); + function up( schema, query ) { + schema.create( + "cb_jwt", + ( table ) => { + table.string( "id", 36 ).primaryKey(); + table.datetime( "expiration" ); + table.datetime( "issued" ); + table.longtext( "token" ); + table.string( "cacheKey" ); + table.string( "subject" ); - // Indexes - table.index( [ "cacheKey" ], "idx_cacheKey" ); - } ); + table.index( [ "cacheKey"], "idx_cacheKey" ); + } + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_login_attempts.cfc b/modules/contentbox/migrations/init/create_login_attempts.cfc index ef5869bbd4..2dad9a6b3e 100644 --- a/modules/contentbox/migrations/init/create_login_attempts.cfc +++ b/modules/contentbox/migrations/init/create_login_attempts.cfc @@ -1,20 +1,21 @@ component { - function up( schema, query ){ - schema.create( "cb_loginAttempts", ( table ) => { - // Base Columns - table.string( "loginAttemptsID", 36 ).primaryKey(); - table.datetime( "createdDate" ).withCurrent(); - table.datetime( "modifiedDate" ).withCurrent(); - table.boolean( "isDeleted" ).default( false ); + function up( schema, query ) { + schema.create( + "cb_loginAttempts", + ( table ) => { + table.string( "loginAttemptsID", 36 ).primaryKey(); + table.datetime( "createdDate" ).withCurrent(); + table.datetime( "modifiedDate" ).withCurrent(); + table.boolean( "isDeleted" ).default( false ); - table.string( "value" ); - table.bigInteger( "attempts" ); - table.string( "lastLoginSuccessIP", 100 ).nullable(); + table.string( "value" ); + table.bigInteger( "attempts" ); + table.string( "lastLoginSuccessIP", 100 ).nullable(); - // Index - table.index( [ "value" ], "idx_values" ); - } ); + table.index( [ "value"], "idx_values" ); + } + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_menu_items.cfc b/modules/contentbox/migrations/init/create_menu_items.cfc index 2f01dab225..83c43f5918 100755 --- a/modules/contentbox/migrations/init/create_menu_items.cfc +++ b/modules/contentbox/migrations/init/create_menu_items.cfc @@ -1,43 +1,43 @@ component { - function up( schema, query ){ - schema.create( "cb_menuItem", ( table ) => { - // Base Columns - table.string( "menuItemID", 36 ).primaryKey(); - table.datetime( "createdDate" ).withCurrent(); - table.datetime( "modifiedDate" ).withCurrent(); - table.boolean( "isDeleted" ).default( false ); + function up( schema, query ) { + schema.create( + "cb_menuItem", + ( table ) => { + table.string( "menuItemID", 36 ).primaryKey(); + table.datetime( "createdDate" ).withCurrent(); + table.datetime( "modifiedDate" ).withCurrent(); + table.boolean( "isDeleted" ).default( false ); - table.boolean( "active" ).default( false ); - table.string( "title", 200 ); - table.string( "label", 200 ).nullable(); - table.string( "itemClass", 200 ).nullable(); - table.string( "data", 200 ).nullable(); - table.string( "menuType" ); - table.string( "menuSlug" ).nullable(); - table.string( "mediaPath" ).nullable(); - table.string( "contentSlug" ).nullable(); - table.string( "url" ).nullable(); - table.string( "js" ).nullable(); - table.string( "target" ).nullable(); - table.string( "urlClass" ).nullable(); + table.boolean( "active" ).default( false ); + table.string( "title", 200 ); + table.string( "label", 200 ).nullable(); + table.string( "itemClass", 200 ).nullable(); + table.string( "data", 200 ).nullable(); + table.string( "menuType" ); + table.string( "menuSlug" ).nullable(); + table.string( "mediaPath" ).nullable(); + table.string( "contentSlug" ).nullable(); + table.string( "url" ).nullable(); + table.string( "js" ).nullable(); + table.string( "target" ).nullable(); + table.string( "urlClass" ).nullable(); - // Relationships - table.string( "FK_menuID", 36 ); - table - .foreignKey( "FK_menuID" ) - .references( "menuID" ) - .onTable( "cb_menu" ); - table.string( "FK_parentID", 36 ).nullable(); - table - .foreignKey( "FK_parentID" ) - .references( "menuItemID" ) - .onTable( "cb_menuItem" ); + table.string( "FK_menuID", 36 ); + table + .foreignKey( "FK_menuID" ) + .references( "menuID" ) + .onTable( "cb_menu" ); + table.string( "FK_parentID", 36 ).nullable(); + table + .foreignKey( "FK_parentID" ) + .references( "menuItemID" ) + .onTable( "cb_menuItem" ); - // Index - table.index( [ "title" ], "idx_menuItemTitle" ); - table.index( [ "isDeleted" ], "idx_menuitems_deleted" ); - } ); + table.index( [ "title"], "idx_menuItemTitle" ); + table.index( [ "isDeleted"], "idx_menuitems_deleted" ); + } + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_menus.cfc b/modules/contentbox/migrations/init/create_menus.cfc index a98fedec91..f82d15bcd6 100644 --- a/modules/contentbox/migrations/init/create_menus.cfc +++ b/modules/contentbox/migrations/init/create_menus.cfc @@ -1,30 +1,30 @@ component { - function up( schema, query ){ - schema.create( "cb_menu", ( table ) => { - // Base Columns - table.string( "menuID", 36 ).primaryKey(); - table.datetime( "createdDate" ).withCurrent(); - table.datetime( "modifiedDate" ).withCurrent(); - table.boolean( "isDeleted" ).default( false ); + function up( schema, query ) { + schema.create( + "cb_menu", + ( table ) => { + table.string( "menuID", 36 ).primaryKey(); + table.datetime( "createdDate" ).withCurrent(); + table.datetime( "modifiedDate" ).withCurrent(); + table.boolean( "isDeleted" ).default( false ); - table.string( "title", 200 ); - table.string( "slug", 200 ); - table.string( "menuClass", 160 ).nullable(); - table.string( "listClass", 160 ).nullable(); - table.string( "listType", 20 ).nullable(); + table.string( "title", 200 ); + table.string( "slug", 200 ); + table.string( "menuClass", 160 ).nullable(); + table.string( "listClass", 160 ).nullable(); + table.string( "listType", 20 ).nullable(); - // Relationships - table.string( "FK_siteID", 36 ); - table - .foreignKey( "FK_siteID" ) - .references( "siteID" ) - .onTable( "cb_site" ); + table.string( "FK_siteID", 36 ); + table + .foreignKey( "FK_siteID" ) + .references( "siteID" ) + .onTable( "cb_site" ); - // Index - table.index( [ "title" ], "idx_menutitle" ); - table.index( [ "slug" ], "idx_menuslug" ); - } ); + table.index( [ "title"], "idx_menutitle" ); + table.index( [ "slug"], "idx_menuslug" ); + } + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_modules.cfc b/modules/contentbox/migrations/init/create_modules.cfc index 03ec87f9bf..59bdd2ce11 100755 --- a/modules/contentbox/migrations/init/create_modules.cfc +++ b/modules/contentbox/migrations/init/create_modules.cfc @@ -1,31 +1,32 @@ component { - function up( schema, query ){ - schema.create( "cb_module", ( table ) => { - // Base Columns - table.string( "moduleID", 36 ).primaryKey(); - table.datetime( "createdDate" ).withCurrent(); - table.datetime( "modifiedDate" ).withCurrent(); - table.boolean( "isDeleted" ).default( false ); + function up( schema, query ) { + schema.create( + "cb_module", + ( table ) => { + table.string( "moduleID", 36 ).primaryKey(); + table.datetime( "createdDate" ).withCurrent(); + table.datetime( "modifiedDate" ).withCurrent(); + table.boolean( "isDeleted" ).default( false ); - table.string( "name" ); - table.string( "title" ).nullable(); - table.string( "version" ).nullable(); - table.string( "entryPoint" ).nullable(); - table.string( "author" ).nullable(); - table.string( "webURL", 500 ).nullable(); - table.string( "forgeBoxSlug" ).nullable(); - table.longText( "description" ).nullable(); - table.boolean( "isActive" ).default( false ); - table.string( "moduleType" ).nullable(); + table.string( "name" ); + table.string( "title" ).nullable(); + table.string( "version" ).nullable(); + table.string( "entryPoint" ).nullable(); + table.string( "author" ).nullable(); + table.string( "webURL", 500 ).nullable(); + table.string( "forgeBoxSlug" ).nullable(); + table.longText( "description" ).nullable(); + table.boolean( "isActive" ).default( false ); + table.string( "moduleType" ).nullable(); - // Indexes - table.index( [ "name" ], "idx_moduleName" ); - table.index( [ "entryPoint" ], "idx_entryPoint" ); - table.index( [ "isActive" ], "idx_activeModule" ); - table.index( [ "moduleType" ], "idx_moduleType" ); - table.index( [ "isDeleted" ], "idx_modules_deleted" ); - } ); + table.index( [ "name"], "idx_moduleName" ); + table.index( [ "entryPoint"], "idx_entryPoint" ); + table.index( [ "isActive"], "idx_activeModule" ); + table.index( [ "moduleType"], "idx_moduleType" ); + table.index( [ "isDeleted"], "idx_modules_deleted" ); + } + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_page.cfc b/modules/contentbox/migrations/init/create_page.cfc index 019b5b93e8..0c43ee4023 100644 --- a/modules/contentbox/migrations/init/create_page.cfc +++ b/modules/contentbox/migrations/init/create_page.cfc @@ -1,25 +1,28 @@ component { - function up( schema, query ){ - schema.create( "cb_page", function( table ){ - table.string( "contentID", 36 ).primaryKey(); - table.boolean( "showInMenu" ).default( true ); - table - .integer( "order" ) - .default( 0 ) - .nullable(); - table.longtext( "excerpt" ).nullable(); - table.string( "layout", 200 ).nullable(); + function up( schema, query ) { + schema.create( + "cb_page", + function( table ) { + table.string( "contentID", 36 ).primaryKey(); + table.boolean( "showInMenu" ).default( true ); + table + .integer( "order" ) + .default( 0 ) + .nullable(); + table.longtext( "excerpt" ).nullable(); + table.string( "layout", 200 ).nullable(); - // Relationships - table - .foreignKey( "contentID" ) - .references( "contentID" ) - .onTable( "cb_content" ); - } ); + table + .foreignKey( "contentID" ) + .references( "contentID" ) + .onTable( "cb_content" ); + } + ); } - function down( schema, query ){ + function down( schema, query ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_permission_groups.cfc b/modules/contentbox/migrations/init/create_permission_groups.cfc index 205544d2e9..b9f96929c9 100644 --- a/modules/contentbox/migrations/init/create_permission_groups.cfc +++ b/modules/contentbox/migrations/init/create_permission_groups.cfc @@ -1,19 +1,22 @@ component { - function up( schema, query ){ - schema.create( "cb_permissionGroup", function( table ){ - // Base Columns - table.string( "permissionGroupID", 36 ).primaryKey(); - table.datetime( "createdDate" ).withCurrent(); - table.datetime( "modifiedDate" ).withCurrent(); - table.boolean( "isDeleted" ).default( false ); + function up( schema, query ) { + schema.create( + "cb_permissionGroup", + function( table ) { + table.string( "permissionGroupID", 36 ).primaryKey(); + table.datetime( "createdDate" ).withCurrent(); + table.datetime( "modifiedDate" ).withCurrent(); + table.boolean( "isDeleted" ).default( false ); - table.string( "name" ).unique(); - table.longText( "description" ).nullable(); - } ); + table.string( "name" ).unique(); + table.longText( "description" ).nullable(); + } + ); } - function down( schema, query ){ + function down( schema, query ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_permissions.cfc b/modules/contentbox/migrations/init/create_permissions.cfc index b8dda8be65..fc4ef98efc 100644 --- a/modules/contentbox/migrations/init/create_permissions.cfc +++ b/modules/contentbox/migrations/init/create_permissions.cfc @@ -1,19 +1,22 @@ component { - function up( schema, query ){ - schema.create( "cb_permission", function( table ){ - // Base Columns - table.string( "permissionID", 36 ).primaryKey(); - table.datetime( "createdDate" ).withCurrent(); - table.datetime( "modifiedDate" ).withCurrent(); - table.boolean( "isDeleted" ).default( false ); + function up( schema, query ) { + schema.create( + "cb_permission", + function( table ) { + table.string( "permissionID", 36 ).primaryKey(); + table.datetime( "createdDate" ).withCurrent(); + table.datetime( "modifiedDate" ).withCurrent(); + table.boolean( "isDeleted" ).default( false ); - table.string( "permission" ).unique(); - table.longText( "description" ).nullable(); - } ); + table.string( "permission" ).unique(); + table.longText( "description" ).nullable(); + } + ); } - function down( schema, query ){ + function down( schema, query ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_related_content.cfc b/modules/contentbox/migrations/init/create_related_content.cfc index a64f04e017..f7a684b51d 100644 --- a/modules/contentbox/migrations/init/create_related_content.cfc +++ b/modules/contentbox/migrations/init/create_related_content.cfc @@ -1,22 +1,26 @@ component { - function up( schema, query ){ - schema.create( "cb_relatedContent", function( table ){ - table.string( "FK_contentID", 36 ); - table.string( "FK_relatedContentID", 36 ); + function up( schema, query ) { + schema.create( + "cb_relatedContent", + function( table ) { + table.string( "FK_contentID", 36 ); + table.string( "FK_relatedContentID", 36 ); - table - .foreignKey( "FK_contentID" ) - .references( "contentID" ) - .onTable( "cb_content" ); - table - .foreignKey( "FK_relatedContentID" ) - .references( "contentID" ) - .onTable( "cb_content" ); - } ); + table + .foreignKey( "FK_contentID" ) + .references( "contentID" ) + .onTable( "cb_content" ); + table + .foreignKey( "FK_relatedContentID" ) + .references( "contentID" ) + .onTable( "cb_content" ); + } + ); } - function down( schema, query ){ + function down( schema, query ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_relocations.cfc b/modules/contentbox/migrations/init/create_relocations.cfc index a22bd43482..7c4d55e62b 100644 --- a/modules/contentbox/migrations/init/create_relocations.cfc +++ b/modules/contentbox/migrations/init/create_relocations.cfc @@ -4,34 +4,36 @@ */ component { - function up( schema, qb ){ - schema.create( "cb_relocations", ( table ) => { - table.string( "relocationID", 36 ).primaryKey(); - table.datetime( "createdDate" ).withCurrent(); - table.datetime( "modifiedDate" ).withCurrent(); - table.boolean( "isDeleted" ).default( false ); + function up( schema, qb ) { + schema.create( + "cb_relocations", + ( table ) => { + table.string( "relocationID", 36 ).primaryKey(); + table.datetime( "createdDate" ).withCurrent(); + table.datetime( "modifiedDate" ).withCurrent(); + table.boolean( "isDeleted" ).default( false ); - table.string( "slug", 500 ); - table.string( "target", 500 ).nullable(); + table.string( "slug", 500 ); + table.string( "target", 500 ).nullable(); - // Relationships - table.string( "FK_siteID", 36 ); - table - .foreignKey( "FK_siteID" ) - .references( "siteID" ) - .onTable( "cb_site" ); - table.string( "FK_contentID", 36 ).nullable(); - table - .foreignKey( "FK_contentID" ) - .references( "contentID" ) - .onTable( "cb_content" ); + table.string( "FK_siteID", 36 ); + table + .foreignKey( "FK_siteID" ) + .references( "siteID" ) + .onTable( "cb_site" ); + table.string( "FK_contentID", 36 ).nullable(); + table + .foreignKey( "FK_contentID" ) + .references( "contentID" ) + .onTable( "cb_content" ); - // Indexes - table.unique( [ "slug", "FK_siteID" ] ); - } ); + table.unique( [ "slug", "FK_siteID"] ); + } + ); } - function down( schema, qb ){ + function down( schema, qb ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_role_permissions.cfc b/modules/contentbox/migrations/init/create_role_permissions.cfc index 396f1c87ea..0a1f81c99f 100644 --- a/modules/contentbox/migrations/init/create_role_permissions.cfc +++ b/modules/contentbox/migrations/init/create_role_permissions.cfc @@ -1,22 +1,26 @@ component { - function up( schema, query ){ - schema.create( "cb_rolePermissions", function( table ){ - table.string( "FK_permissionID", 36 ); - table.string( "FK_roleID", 36 ); + function up( schema, query ) { + schema.create( + "cb_rolePermissions", + function( table ) { + table.string( "FK_permissionID", 36 ); + table.string( "FK_roleID", 36 ); - table - .foreignKey( "FK_permissionID" ) - .references( "permissionID" ) - .onTable( "cb_permission" ); - table - .foreignKey( "FK_roleID" ) - .references( "roleID" ) - .onTable( "cb_role" ); - } ); + table + .foreignKey( "FK_permissionID" ) + .references( "permissionID" ) + .onTable( "cb_permission" ); + table + .foreignKey( "FK_roleID" ) + .references( "roleID" ) + .onTable( "cb_role" ); + } + ); } - function down( schema, query ){ + function down( schema, query ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_roles.cfc b/modules/contentbox/migrations/init/create_roles.cfc index 143467548d..a7f0b9ca8b 100644 --- a/modules/contentbox/migrations/init/create_roles.cfc +++ b/modules/contentbox/migrations/init/create_roles.cfc @@ -1,19 +1,22 @@ component { - function up( schema, query ){ - schema.create( "cb_role", function( table ){ - // Base Columns - table.string( "roleID", 36 ).primaryKey(); - table.datetime( "createdDate" ).withCurrent(); - table.datetime( "modifiedDate" ).withCurrent(); - table.boolean( "isDeleted" ).default( false ); + function up( schema, query ) { + schema.create( + "cb_role", + function( table ) { + table.string( "roleID", 36 ).primaryKey(); + table.datetime( "createdDate" ).withCurrent(); + table.datetime( "modifiedDate" ).withCurrent(); + table.boolean( "isDeleted" ).default( false ); - table.string( "role" ).unique(); - table.longText( "description" ).nullable(); - } ); + table.string( "role" ).unique(); + table.longText( "description" ).nullable(); + } + ); } - function down( schema, query ){ + function down( schema, query ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_security_logs.cfc b/modules/contentbox/migrations/init/create_security_logs.cfc index 0aeed0a3bb..ceee1fc19a 100644 --- a/modules/contentbox/migrations/init/create_security_logs.cfc +++ b/modules/contentbox/migrations/init/create_security_logs.cfc @@ -1,32 +1,33 @@ component { - function up( schema, query ){ - schema.create( "cbsecurity_logs", ( table ) => { - // Base Columns - table.string( "id", 36 ).primaryKey(); - table.datetime( "logDate" ).withCurrent(); - table.longText( "securityRule" ); - table.string( "action", 20 ); - table.string( "blockType", 20 ); - table.string( "ip", 100 ); - table.string( "host" ); - table.string( "httpMethod", 25 ); - table.string( "path" ); - table.string( "queryString" ); - table.string( "referer" ); - table.string( "userAgent" ); - table.string( "userId", 36 ); + function up( schema, query ) { + schema.create( + "cbsecurity_logs", + ( table ) => { + table.string( "id", 36 ).primaryKey(); + table.datetime( "logDate" ).withCurrent(); + table.longText( "securityRule" ); + table.string( "action", 20 ); + table.string( "blockType", 20 ); + table.string( "ip", 100 ); + table.string( "host" ); + table.string( "httpMethod", 25 ); + table.string( "path" ); + table.string( "queryString" ); + table.string( "referer" ); + table.string( "userAgent" ); + table.string( "userId", 36 ); - // Index - table.index( [ "logDate", "action", "blockType" ], "idx_cbsecurity" ); - table.index( [ "userId" ], "idx_cbsecurity_userId" ); - table.index( [ "userAgent" ], "idx_cbsecurity_userAgent" ); - table.index( [ "ip" ], "idx_cbsecurity_ip" ); - table.index( [ "host" ], "idx_cbsecurity_host" ); - table.index( [ "httpMethod" ], "idx_cbsecurity_httpMethod" ); - table.index( [ "path" ], "idx_cbsecurity_path" ); - table.index( [ "referer" ], "idx_cbsecurity_referer" ); - } ); + table.index( [ "logDate", "action", "blockType"], "idx_cbsecurity" ); + table.index( [ "userId"], "idx_cbsecurity_userId" ); + table.index( [ "userAgent"], "idx_cbsecurity_userAgent" ); + table.index( [ "ip"], "idx_cbsecurity_ip" ); + table.index( [ "host"], "idx_cbsecurity_host" ); + table.index( [ "httpMethod"], "idx_cbsecurity_httpMethod" ); + table.index( [ "path"], "idx_cbsecurity_path" ); + table.index( [ "referer"], "idx_cbsecurity_referer" ); + } + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_security_rules.cfc b/modules/contentbox/migrations/init/create_security_rules.cfc index d2300a9479..f1b6612b06 100755 --- a/modules/contentbox/migrations/init/create_security_rules.cfc +++ b/modules/contentbox/migrations/init/create_security_rules.cfc @@ -1,44 +1,45 @@ component { - function up( schema, query ){ - schema.create( "cb_securityRule", ( table ) => { - // Base Columns - table.string( "ruleID", 36 ).primaryKey(); - table.datetime( "createdDate" ).withCurrent(); - table.datetime( "modifiedDate" ).withCurrent(); - table.boolean( "isDeleted" ).default( false ); + function up( schema, query ) { + schema.create( + "cb_securityRule", + ( table ) => { + table.string( "ruleID", 36 ).primaryKey(); + table.datetime( "createdDate" ).withCurrent(); + table.datetime( "modifiedDate" ).withCurrent(); + table.boolean( "isDeleted" ).default( false ); - table.string( "whitelist" ).nullable(); - table.string( "securelist" ); - table.string( "match", 50 ).nullable(); - table.string( "roles", 500 ).nullable(); - table.string( "permissions", 500 ).nullable(); - table.string( "redirect", 500 ).nullable(); - table.string( "overrideEvent", 500 ).nullable(); - table.boolean( "useSSL" ).default( false ); - table - .string( "action", 50 ) - .nullable() - .default( "redirect" ); - table.string( "module", 500 ).nullable(); - table - .string( "httpMethods" ) - .nullable() - .default( "*" ); - table - .string( "allowedIPs" ) - .nullable() - .default( "*" ); - table.integer( "order" ).default( 0 ); - table.string( "message" ).nullable(); - table - .string( "messageType", 50 ) - .nullable() - .default( "info" ); + table.string( "whitelist" ).nullable(); + table.string( "securelist" ); + table.string( "match", 50 ).nullable(); + table.string( "roles", 500 ).nullable(); + table.string( "permissions", 500 ).nullable(); + table.string( "redirect", 500 ).nullable(); + table.string( "overrideEvent", 500 ).nullable(); + table.boolean( "useSSL" ).default( false ); + table + .string( "action", 50 ) + .nullable() + .default( "redirect" ); + table.string( "module", 500 ).nullable(); + table + .string( "httpMethods" ) + .nullable() + .default( "*" ); + table + .string( "allowedIPs" ) + .nullable() + .default( "*" ); + table.integer( "order" ).default( 0 ); + table.string( "message" ).nullable(); + table + .string( "messageType", 50 ) + .nullable() + .default( "info" ); - // Indexes - table.index( [ "isDeleted" ], "idx_securityrules_deleted" ); - } ); + table.index( [ "isDeleted"], "idx_securityrules_deleted" ); + } + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_settings.cfc b/modules/contentbox/migrations/init/create_settings.cfc index a9cfc6cc26..2d98bc9e2d 100755 --- a/modules/contentbox/migrations/init/create_settings.cfc +++ b/modules/contentbox/migrations/init/create_settings.cfc @@ -1,28 +1,28 @@ component { - function up( schema, query ){ - schema.create( "cb_setting", ( table ) => { - // Base Columns - table.string( "settingID", 36 ).primaryKey(); - table.datetime( "createdDate" ).withCurrent(); - table.datetime( "modifiedDate" ).withCurrent(); - table.boolean( "isDeleted" ).default( false ); + function up( schema, query ) { + schema.create( + "cb_setting", + ( table ) => { + table.string( "settingID", 36 ).primaryKey(); + table.datetime( "createdDate" ).withCurrent(); + table.datetime( "modifiedDate" ).withCurrent(); + table.boolean( "isDeleted" ).default( false ); - table.string( "name" ); - table.longText( "value" ); - table.boolean( "isCore" ).default( false ); + table.string( "name" ); + table.longText( "value" ); + table.boolean( "isCore" ).default( false ); - // Relationships - table.string( "FK_siteID", 36 ).nullable(); - table - .foreignKey( "FK_siteID" ) - .references( "siteID" ) - .onTable( "cb_site" ); + table.string( "FK_siteID", 36 ).nullable(); + table + .foreignKey( "FK_siteID" ) + .references( "siteID" ) + .onTable( "cb_site" ); - // Indexes - table.index( [ "isCore" ], "idx_core" ); - table.index( [ "isDeleted" ], "idx_settings_deleted" ); - } ); + table.index( [ "isCore"], "idx_core" ); + table.index( [ "isDeleted"], "idx_settings_deleted" ); + } + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_sites.cfc b/modules/contentbox/migrations/init/create_sites.cfc index aca4324c90..4af104acb6 100755 --- a/modules/contentbox/migrations/init/create_sites.cfc +++ b/modules/contentbox/migrations/init/create_sites.cfc @@ -1,39 +1,40 @@ component { - function up( schema, query ){ - schema.create( "cb_site", ( table ) => { - // Base Columns - table.string( "siteID", 36 ).primaryKey(); - table.datetime( "createdDate" ).withCurrent(); - table.datetime( "modifiedDate" ).withCurrent(); - table.boolean( "isDeleted" ).default( false ); + function up( schema, query ) { + schema.create( + "cb_site", + ( table ) => { + table.string( "siteID", 36 ).primaryKey(); + table.datetime( "createdDate" ).withCurrent(); + table.datetime( "modifiedDate" ).withCurrent(); + table.boolean( "isDeleted" ).default( false ); - table.string( "name" ); - table.string( "slug" ).unique(); - table.longText( "description" ).nullable(); - table.string( "domainRegex" ).nullable(); - table.string( "keywords" ).nullable(); - table.string( "tagline" ).nullable(); - table.string( "homepage" ).nullable(); - table.boolean( "isBlogEnabled" ).default( true ); - table.boolean( "isSitemapEnabled" ).default( true ); - table.boolean( "poweredByHeader" ).default( true ); - table.boolean( "adminBar" ).default( true ); - table.boolean( "isSSL" ).default( false ); - table.string( "activeTheme" ).nullable(); - table.longText( "notificationEmails" ).nullable(); - table.boolean( "notifyOnEntries" ).default( true ); - table.boolean( "notifyOnPages" ).default( true ); - table.boolean( "notifyOnContentStore" ).default( true ); - table.string( "domain" ).nullable(); - table.boolean( "isActive" ).default( true ); - table.string( "mediaDisk", 50 ).nullable(); - table.text( "domainAliases" ).nullable(); + table.string( "name" ); + table.string( "slug" ).unique(); + table.longText( "description" ).nullable(); + table.string( "domainRegex" ).nullable(); + table.string( "keywords" ).nullable(); + table.string( "tagline" ).nullable(); + table.string( "homepage" ).nullable(); + table.boolean( "isBlogEnabled" ).default( true ); + table.boolean( "isSitemapEnabled" ).default( true ); + table.boolean( "poweredByHeader" ).default( true ); + table.boolean( "adminBar" ).default( true ); + table.boolean( "isSSL" ).default( false ); + table.string( "activeTheme" ).nullable(); + table.longText( "notificationEmails" ).nullable(); + table.boolean( "notifyOnEntries" ).default( true ); + table.boolean( "notifyOnPages" ).default( true ); + table.boolean( "notifyOnContentStore" ).default( true ); + table.string( "domain" ).nullable(); + table.boolean( "isActive" ).default( true ); + table.string( "mediaDisk", 50 ).nullable(); + table.text( "domainAliases" ).nullable(); - // Indexes - table.index( [ "slug" ], "idx_siteSlug" ); - table.index( [ "isDeleted" ], "idx_sites_deleted" ); - } ); + table.index( [ "slug"], "idx_siteSlug" ); + table.index( [ "isDeleted"], "idx_sites_deleted" ); + } + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_stats.cfc b/modules/contentbox/migrations/init/create_stats.cfc index ab092577aa..b147990ffd 100755 --- a/modules/contentbox/migrations/init/create_stats.cfc +++ b/modules/contentbox/migrations/init/create_stats.cfc @@ -1,28 +1,29 @@ component { - function up( schema, query ){ - schema.create( "cb_stats", function( table ){ - // Base Columns - table.string( "statsID", 36 ).primaryKey(); - table.datetime( "createdDate" ).withCurrent(); - table.datetime( "modifiedDate" ).withCurrent(); - table.boolean( "isDeleted" ).default( false ); + function up( schema, query ) { + schema.create( + "cb_stats", + function( table ) { + table.string( "statsID", 36 ).primaryKey(); + table.datetime( "createdDate" ).withCurrent(); + table.datetime( "modifiedDate" ).withCurrent(); + table.boolean( "isDeleted" ).default( false ); - table.bigInteger( "hits" ).default( 0 ); + table.bigInteger( "hits" ).default( 0 ); - // Relationships - table.string( "FK_contentID", 36 ); - table - .foreignKey( "FK_contentID" ) - .references( "contentID" ) - .onTable( "cb_content" ); + table.string( "FK_contentID", 36 ); + table + .foreignKey( "FK_contentID" ) + .references( "contentID" ) + .onTable( "cb_content" ); - // Index - table.index( [ "isDeleted" ], "idx_stats_deleted" ); - } ); + table.index( [ "isDeleted"], "idx_stats_deleted" ); + } + ); } - function down( schema, query ){ + function down( schema, query ) { + } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_subscribers.cfc b/modules/contentbox/migrations/init/create_subscribers.cfc index a400845436..918c097ea3 100755 --- a/modules/contentbox/migrations/init/create_subscribers.cfc +++ b/modules/contentbox/migrations/init/create_subscribers.cfc @@ -1,20 +1,21 @@ component { - function up( schema, query ){ - schema.create( "cb_subscribers", ( table ) => { - // Base Columns - table.string( "subscriberID", 36 ).primaryKey(); - table.datetime( "createdDate" ).withCurrent(); - table.datetime( "modifiedDate" ).withCurrent(); - table.boolean( "isDeleted" ).default( false ); + function up( schema, query ) { + schema.create( + "cb_subscribers", + ( table ) => { + table.string( "subscriberID", 36 ).primaryKey(); + table.datetime( "createdDate" ).withCurrent(); + table.datetime( "modifiedDate" ).withCurrent(); + table.boolean( "isDeleted" ).default( false ); - table.string( "subscriberEmail" ); - table.string( "subscriberToken" ); + table.string( "subscriberEmail" ); + table.string( "subscriberToken" ); - // Indexes - table.index( [ "subscriberEmail" ], "idx_subscriberEmail" ); - table.index( [ "isDeleted" ], "idx_subscribers_deleted" ); - } ); + table.index( [ "subscriberEmail"], "idx_subscriberEmail" ); + table.index( [ "isDeleted"], "idx_subscribers_deleted" ); + } + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_subscriptions.cfc b/modules/contentbox/migrations/init/create_subscriptions.cfc index c778b81263..f1d1c5d3c3 100755 --- a/modules/contentbox/migrations/init/create_subscriptions.cfc +++ b/modules/contentbox/migrations/init/create_subscriptions.cfc @@ -1,26 +1,26 @@ component { - function up( schema, query ){ - schema.create( "cb_subscriptions", ( table ) => { - // Base Columns - table.string( "subscriptionID", 36 ).primaryKey(); - table.datetime( "createdDate" ).withCurrent(); - table.datetime( "modifiedDate" ).withCurrent(); - table.boolean( "isDeleted" ).default( false ); + function up( schema, query ) { + schema.create( + "cb_subscriptions", + ( table ) => { + table.string( "subscriptionID", 36 ).primaryKey(); + table.datetime( "createdDate" ).withCurrent(); + table.datetime( "modifiedDate" ).withCurrent(); + table.boolean( "isDeleted" ).default( false ); - table.string( "type" ); - table.string( "subscriptionToken" ); + table.string( "type" ); + table.string( "subscriptionToken" ); - // Relationships - table.string( "FK_subscriberID", 36 ); - table - .foreignKey( "FK_subscriberID" ) - .references( "subscriberID" ) - .onTable( "cb_subscribers" ); + table.string( "FK_subscriberID", 36 ); + table + .foreignKey( "FK_subscriberID" ) + .references( "subscriberID" ) + .onTable( "cb_subscribers" ); - // Indexes - table.index( [ "isDeleted" ], "idx_subscriptions_deleted" ); - } ); + table.index( [ "isDeleted"], "idx_subscriptions_deleted" ); + } + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/create_users.cfc b/modules/contentbox/migrations/init/create_users.cfc index 865002d8d6..c025225b0e 100644 --- a/modules/contentbox/migrations/init/create_users.cfc +++ b/modules/contentbox/migrations/init/create_users.cfc @@ -1,47 +1,50 @@ component { - function up( schema, query ){ - schema.create( "user", function( table ){ - table.string( "userId" ).primaryKey(); - table.string( "userType", 50 ); - table.datetime( "createdDate" ).withCurrent(); - table.datetime( "modifiedDate" ).withCurrent(); - table.tinyInteger( "isActive", 1 ).default( 1 ); - table.string( "fname", 100 ); - table.string( "lname", 100 ); - table.string( "title" ); - table.string( "email" ).unique(); - table.string( "password" ); - table.datetime( "lastLogin" ).nullable(); - table.string( "mobilePhone", 100 ).nullable(); - table.string( "homePhone", 100 ).nullable(); - table.date( "dob", 100 ).nullable(); - table.string( "tshirtSize", 100 ).nullable(); - table - .longText( "preferences" ) - .default( "" ) - .nullable(); - table.string( "facebookURL" ).nullable(); - table.string( "twitterURL" ).nullable(); - table.string( "blogURL" ).nullable(); - table.string( "linkedinURL" ).nullable(); - table.string( "githubURL" ).nullable(); - table.tinyInteger( "isPasswordReset", 1 ).default( 1 ); - table.longText( "biography" ).nullable(); - table.string( "address" ).nullable(); - table.string( "city", 75 ).nullable(); - table.string( "stateOrProvince" ).nullable(); - table.string( "postalCode" ).nullable(); - table.string( "country", 75 ); - table.string( "timeZone", 150 ); - table.string( "FK_roleId" ); - table.string( "FK_clientId" ).nullable(); - table.string( "FK_managerId" ).nullable(); - } ); + function up( schema, query ) { + schema.create( + "user", + function( table ) { + table.string( "userId" ).primaryKey(); + table.string( "userType", 50 ); + table.datetime( "createdDate" ).withCurrent(); + table.datetime( "modifiedDate" ).withCurrent(); + table.tinyInteger( "isActive", 1 ).default( 1 ); + table.string( "fname", 100 ); + table.string( "lname", 100 ); + table.string( "title" ); + table.string( "email" ).unique(); + table.string( "password" ); + table.datetime( "lastLogin" ).nullable(); + table.string( "mobilePhone", 100 ).nullable(); + table.string( "homePhone", 100 ).nullable(); + table.date( "dob", 100 ).nullable(); + table.string( "tshirtSize", 100 ).nullable(); + table + .longText( "preferences" ) + .default( "" ) + .nullable(); + table.string( "facebookURL" ).nullable(); + table.string( "twitterURL" ).nullable(); + table.string( "blogURL" ).nullable(); + table.string( "linkedinURL" ).nullable(); + table.string( "githubURL" ).nullable(); + table.tinyInteger( "isPasswordReset", 1 ).default( 1 ); + table.longText( "biography" ).nullable(); + table.string( "address" ).nullable(); + table.string( "city", 75 ).nullable(); + table.string( "stateOrProvince" ).nullable(); + table.string( "postalCode" ).nullable(); + table.string( "country", 75 ); + table.string( "timeZone", 150 ); + table.string( "FK_roleId" ); + table.string( "FK_clientId" ).nullable(); + table.string( "FK_managerId" ).nullable(); + } + ); } - function down( schema, query ){ + function down( schema, query ) { schema.drop( "user" ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/seed_permissions.cfc b/modules/contentbox/migrations/init/seed_permissions.cfc index a277304abe..48fdc81607 100644 --- a/modules/contentbox/migrations/init/seed_permissions.cfc +++ b/modules/contentbox/migrations/init/seed_permissions.cfc @@ -1,200 +1,203 @@ component { - function seed( schema, query ){ + function seed( schema, query ) { var perms = [ { - "permission" : "AUTHOR_ADMIN", - "description" : "Ability to manage authors, default is view only" + "permission" : "AUTHOR_ADMIN", + "description": "Ability to manage authors, default is view only" }, { - "permission" : "CATEGORIES_ADMIN", - "description" : "Ability to manage categories, default is view only" + "permission" : "CATEGORIES_ADMIN", + "description": "Ability to manage categories, default is view only" }, { - "permission" : "COMMENTS_ADMIN", - "description" : "Ability to manage comments, default is view only" + "permission" : "COMMENTS_ADMIN", + "description": "Ability to manage comments, default is view only" }, { - "permission" : "CONTENTBOX_ADMIN", - "description" : "Access to the enter the ContentBox administrator console" + "permission" : "CONTENTBOX_ADMIN", + "description": "Access to the enter the ContentBox administrator console" }, { - "permission" : "CONTENTSTORE_ADMIN", - "description" : "Ability to manage the content store, default is view only" + "permission" : "CONTENTSTORE_ADMIN", + "description": "Ability to manage the content store, default is view only" }, { - "permission" : "CONTENTSTORE_EDITOR", - "description" : "Ability to create, edit and publish content store elements" + "permission" : "CONTENTSTORE_EDITOR", + "description": "Ability to create, edit and publish content store elements" }, { - "permission" : "EDITORS_CACHING", - "description" : "Ability to view the content caching panel" + "permission" : "EDITORS_CACHING", + "description": "Ability to view the content caching panel" }, { - "permission" : "EDITORS_CATEGORIES", - "description" : "Ability to view the content categories panel" + "permission" : "EDITORS_CATEGORIES", + "description": "Ability to view the content categories panel" }, { - "permission" : "EDITORS_CUSTOM_FIELDS", - "description" : "Ability to manage custom fields in any content editors" + "permission" : "EDITORS_CUSTOM_FIELDS", + "description": "Ability to manage custom fields in any content editors" }, { - "permission" : "EDITORS_DISPLAY_OPTIONS", - "description" : "Ability to view the content display options panel" + "permission" : "EDITORS_DISPLAY_OPTIONS", + "description": "Ability to view the content display options panel" }, { - "permission" : "EDITORS_EDITOR_SELECTOR", - "description" : "Ability to change the editor to another registered online editor" + "permission" : "EDITORS_EDITOR_SELECTOR", + "description": "Ability to change the editor to another registered online editor" }, { - "permission" : "EDITORS_FEATURED_IMAGE", - "description" : "Ability to view the featured image panel" + "permission" : "EDITORS_FEATURED_IMAGE", + "description": "Ability to view the featured image panel" }, { - "permission" : "EDITORS_HTML_ATTRIBUTES", - "description" : "Ability to view the content HTML attributes panel" + "permission" : "EDITORS_HTML_ATTRIBUTES", + "description": "Ability to view the content HTML attributes panel" }, { - "permission" : "EDITORS_LINKED_CONTENT", - "description" : "Ability to view the linked content panel" + "permission" : "EDITORS_LINKED_CONTENT", + "description": "Ability to view the linked content panel" }, { - "permission" : "EDITORS_MODIFIERS", - "description" : "Ability to view the content modifiers panel" + "permission" : "EDITORS_MODIFIERS", + "description": "Ability to view the content modifiers panel" }, { - "permission" : "EDITORS_RELATED_CONTENT", - "description" : "Ability to view the related content panel" + "permission" : "EDITORS_RELATED_CONTENT", + "description": "Ability to view the related content panel" }, { - "permission" : "EMAIL_TEMPLATE_ADMIN", - "description" : "Ability to admin and preview email templates" + "permission" : "EMAIL_TEMPLATE_ADMIN", + "description": "Ability to admin and preview email templates" }, { - "permission" : "ENTRIES_ADMIN", - "description" : "Ability to manage blog entries, default is view only" + "permission" : "ENTRIES_ADMIN", + "description": "Ability to manage blog entries, default is view only" }, { - "permission" : "ENTRIES_EDITOR", - "description" : "Ability to create, edit and publish blog entries" + "permission" : "ENTRIES_EDITOR", + "description": "Ability to create, edit and publish blog entries" }, { - "permission" : "FORGEBOX_ADMIN", - "description" : "Ability to manage ForgeBox installations and connectivity." + "permission" : "FORGEBOX_ADMIN", + "description": "Ability to manage ForgeBox installations and connectivity." }, { - "permission" : "GLOBAL_SEARCH", - "description" : "Ability to do global searches in the ContentBox Admin" + "permission" : "GLOBAL_SEARCH", + "description": "Ability to do global searches in the ContentBox Admin" }, { - "permission" : "GLOBALHTML_ADMIN", - "description" : "Ability to manage the system's global HTML content used on layouts" + "permission" : "GLOBALHTML_ADMIN", + "description": "Ability to manage the system's global HTML content used on layouts" }, { - "permission" : "MEDIAMANAGER_ADMIN", - "description" : "Ability to manage the system's media manager" + "permission" : "MEDIAMANAGER_ADMIN", + "description": "Ability to manage the system's media manager" }, { - "permission" : "MEDIAMANAGER_LIBRARY_SWITCHER", - "description" : "Ability to switch media manager libraries for management" + "permission" : "MEDIAMANAGER_LIBRARY_SWITCHER", + "description": "Ability to switch media manager libraries for management" }, { - "permission" : "MENUS_ADMIN", - "description" : "Ability to manage the menu builder" + "permission" : "MENUS_ADMIN", + "description": "Ability to manage the menu builder" }, { - "permission" : "MODULES_ADMIN", - "description" : "Ability to manage ContentBox Modules" + "permission" : "MODULES_ADMIN", + "description": "Ability to manage ContentBox Modules" }, { - "permission" : "PAGES_ADMIN", - "description" : "Ability to manage content pages, default is view only" + "permission" : "PAGES_ADMIN", + "description": "Ability to manage content pages, default is view only" }, { - "permission" : "PAGES_EDITOR", - "description" : "Ability to create, edit and publish pages" + "permission" : "PAGES_EDITOR", + "description": "Ability to create, edit and publish pages" }, { - "permission" : "PERMISSIONS_ADMIN", - "description" : "Ability to manage permissions, default is view only" + "permission" : "PERMISSIONS_ADMIN", + "description": "Ability to manage permissions, default is view only" }, { - "permission" : "RELOAD_MODULES", - "description" : "Ability to reload modules" + "permission" : "RELOAD_MODULES", + "description": "Ability to reload modules" }, { - "permission" : "RELOAD_CACHES", - "description" : "Ability to reload caches" + "permission" : "RELOAD_CACHES", + "description": "Ability to reload caches" }, { - "permission" : "ROLES_ADMIN", - "description" : "Ability to manage roles, default is view only" + "permission" : "ROLES_ADMIN", + "description": "Ability to manage roles, default is view only" }, { - "permission" : "SECURITYRULES_ADMIN", - "description" : "Ability to manage the system's security rules, default is view only" + "permission" : "SECURITYRULES_ADMIN", + "description": "Ability to manage the system's security rules, default is view only" }, { - "permission" : "SITES_ADMIN", - "description" : "Ability to manage sites" + "permission" : "SITES_ADMIN", + "description": "Ability to manage sites" }, { - "permission" : "SYSTEM_AUTH_LOGS", - "description" : "Access to the system auth logs" + "permission" : "SYSTEM_AUTH_LOGS", + "description": "Access to the system auth logs" }, { - "permission" : "SYSTEM_RAW_SETTINGS", - "description" : "Access to the ContentBox raw geek settings panel" + "permission" : "SYSTEM_RAW_SETTINGS", + "description": "Access to the ContentBox raw geek settings panel" }, { - "permission" : "SYSTEM_SAVE_CONFIGURATION", - "description" : "Ability to update global configuration data" + "permission" : "SYSTEM_SAVE_CONFIGURATION", + "description": "Ability to update global configuration data" }, { - "permission" : "SYSTEM_TAB", - "description" : "Access to the ContentBox System tools" + "permission" : "SYSTEM_TAB", + "description": "Access to the ContentBox System tools" }, { - "permission" : "SYSTEM_UPDATES", - "description" : "Ability to view and apply ContentBox updates" + "permission" : "SYSTEM_UPDATES", + "description": "Ability to view and apply ContentBox updates" }, { - "permission" : "THEME_ADMIN", - "description" : "Ability to manage layouts, default is view only" + "permission" : "THEME_ADMIN", + "description": "Ability to manage layouts, default is view only" }, { - "permission" : "TOOLS_EXPORT", - "description" : "Ability to export data from ContentBox" + "permission" : "TOOLS_EXPORT", + "description": "Ability to export data from ContentBox" }, { - "permission" : "TOOLS_IMPORT", - "description" : "Ability to import data into ContentBox" + "permission" : "TOOLS_IMPORT", + "description": "Ability to import data into ContentBox" }, { - "permission" : "VERSIONS_DELETE", - "description" : "Ability to delete past content versions" + "permission" : "VERSIONS_DELETE", + "description": "Ability to delete past content versions" }, { - "permission" : "VERSIONS_ROLLBACK", - "description" : "Ability to rollback content versions" + "permission" : "VERSIONS_ROLLBACK", + "description": "Ability to rollback content versions" }, { - "permission" : "WIDGET_ADMIN", - "description" : "Ability to manage widgets, default is view only" + "permission" : "WIDGET_ADMIN", + "description": "Ability to manage widgets, default is view only" } - ]; + ] - perms = perms.map( ( thisPerm ) => { - thisPerm[ "permissionID" ] = createUUID(); - thisPerm[ "isDeleted" ] = 0; - thisPerm[ "createdDate" ] = thisPerm[ "modifiedDate" ] = now(); - return thisPerm; - } ); + var falseBinding = query.getGrammar().convertToBooleanType( false ) + perms = perms.map( + ( thisPerm ) => { + thisPerm[ "permissionID" ] = createUUID() + thisPerm[ "isDeleted" ] = falseBinding + thisPerm[ "createdDate" ] = thisPerm[ "modifiedDate" ] = now() + return thisPerm + } + ) query .newQuery() .from( "cb_permission" ) - .insert( perms ); + .insert( perms ) } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/init/seed_roles.cfc b/modules/contentbox/migrations/init/seed_roles.cfc index 92b8e4b871..2b1b364188 100644 --- a/modules/contentbox/migrations/init/seed_roles.cfc +++ b/modules/contentbox/migrations/init/seed_roles.cfc @@ -1,22 +1,25 @@ component { - function seed( schema, query ){ + function seed( schema, query ) { + var falseBinding = query.getGrammar().convertToBooleanType( false ) + var trueBinding = query.getGrammar().convertToBooleanType( true ) + var admin = { - "roleID" : createUUID(), - "isDeleted" : 0, - "createdDate" : now(), - "modifiedDate" : now(), - "role" : "Administrator", - "description" : "A ContentBox Administrator" - }; + "roleID" : createUUID(), + "isDeleted" : falseBinding, + "createdDate" : now(), + "modifiedDate": now(), + "role" : "Administrator", + "description" : "A ContentBox Administrator" + } var editor = { - "roleID" : createUUID(), - "isDeleted" : 0, - "createdDate" : now(), - "modifiedDate" : now(), - "role" : "Editor", - "description" : "A ContentBox Editor" - }; + "roleID" : createUUID(), + "isDeleted" : falseBinding, + "createdDate" : now(), + "modifiedDate": now(), + "role" : "Editor", + "description" : "A ContentBox Editor" + } // ADMIN ROLE @@ -30,15 +33,19 @@ component { .from( "cb_permission" ) .get(); - allPerms.each( ( record ) => { - query - .newQuery() - .from( "cb_rolePermissions" ) - .insert( { - "FK_permissionID" : record.permissionID, - "FK_roleID" : admin.roleID - } ); - } ); + allPerms.each( + ( record ) => { + query + .newQuery() + .from( "cb_rolePermissions" ) + .insert( + { + "FK_permissionID": record.permissionID, + "FK_roleID" : admin.roleID + } + ); + } + ); systemOutput( "√ Admin role and permissions created", true ); @@ -77,22 +84,26 @@ component { "VERSIONS_ROLLBACK" ]; - allPerms - .filter( ( record ) => { - return editorPerms.contains( record.permission ); - } ) - .each( ( record ) => { - query - .newQuery() - .from( "cb_rolePermissions" ) - .insert( { - "FK_permissionID" : record.permissionID, - "FK_roleID" : editor.roleID - } ); - } ); + allPerms.filter( + ( record ) => { + return editorPerms.contains( record.permission ); + } + ).each( + ( record ) => { + query + .newQuery() + .from( "cb_rolePermissions" ) + .insert( + { + "FK_permissionID": record.permissionID, + "FK_roleID" : editor.roleID + } + ); + } + ); systemOutput( "√ Editor role created", true ); systemOutput( "√ Roles seeded", true ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/migrations/util/MigrationUtils.cfm b/modules/contentbox/migrations/util/MigrationUtils.cfm index 0d06855816..16003a345e 100644 --- a/modules/contentbox/migrations/util/MigrationUtils.cfm +++ b/modules/contentbox/migrations/util/MigrationUtils.cfm @@ -1,156 +1,189 @@ -/** - * This utility file is a collection of migration utilities that ContentBox will use - */ + /** + * This utility file is a collection of migration utilities that ContentBox will use + */ -/** - * Get a new java based UUID - */ -function getUUID(){ - if( isNull( variables.uuidLib ) ){ - variables.uuidLib = createObject( "java", "java.util.UUID" ); + /** + * Get a new java based UUID + */ + function getUUID() { + if ( isNull( variables.uuidLib ) ) { + variables.uuidLib = createObject( "java", "java.util.UUID" ); + } + return variables + .uuidLib + .randomUUID() + .toString(); } - return variables.uuidLib.randomUUID().toString(); -} -/** - * Verify if a table has a column or not - * - * @targetTable The table to check - * @targetcolumn The column to check - */ -boolean function hasColumn( targetTable, targetColumn ){ - // Check for column created - cfdbinfo( - name = "local.qSettingColumns", - type = "columns", - table = arguments.targetTable - ); + /** + * Verify if a table has a column or not + * + * @targetTable The table to check + * @targetcolumn The column to check + */ + boolean function hasColumn( targetTable, targetColumn ) { - if ( - qSettingColumns.filter( ( thisRow ) => { - // systemOutput( thisRow, true ); - return thisRow.column_name == targetColumn - } ).recordCount > 0 - ) { - return true; - } - return false; -} + try{ + // Use information_schema directly so the check is dialect-safe and preserves + // identifier case (cfdbinfo lowercases table names which breaks on PostgreSQL). + var result = queryExecute( + "SELECT 1 FROM information_schema.columns WHERE table_name = :tableName AND column_name = :columnName", + { + tableName : arguments.targetTable, + columnName : arguments.targetColumn + } + ) + return result.recordCount > 0 + } catch ( any e ) { + // If not, fall back to the this method. + // Check for column created + dbinfo name ="local.qSettingColumns" type ="columns" table="#arguments.targetTable#"; -/** - * Generate a list of indexes from the database - * - * @schemaName The name of database - * @tableName The name of table from database - * @indexName The index name to search - * @qb QB instance - * @selectOptions The Index columns that we need to show - * - * @return array with database index information - * */ -Array function listIndexesFromSchema( - required string schemaName, - required string tableName, - required string indexName, - required qb, - string selectOptions = "index_name" -){ - return qb.select( arguments.selectOptions ) - .distinct() - .from( "information_schema.statistics" ) - .where( "table_schema", arguments.schemaName ) - .where( "table_name", arguments.tableName ) - .where( "index_name", "like", "%#indexName#%" ) - .get(); -} + if ( + qSettingColumns.filter( + ( thisRow ) => { + return thisRow.column_name == targetColumn; + } + )// systemOutput( thisRow, true ); + + .recordCount > + 0 + ) { + return true + } + return false + } + } -/** - * Drop indexes fron database - * - * @indexes The Array of indexes to delete - * @schema The schema instance from QB - * @tableName The name of table from database - * - * @return void - * */ -function dropIndexesFromSchema( - required array indexes, - required schema, - required string tableName -){ - indexes.each( ( index ) => { - schema.alter( "#tableName#", function( table ) { - table.dropConstraint( table.index( [], "#index.index_name#" ) ); - } ); - } ); -} + /** + * Generate a list of indexes from the database + * + * @schemaName The name of database + * @tableName The name of table from database + * @indexName The index name to search + * @qb QB instance + * @selectOptions The Index columns that we need to show + * + * @return array with database index information + **/ + array function listIndexesFromSchema( + required string schemaName, + required string tableName, + required string indexName, + required qb, + string selectOptions = "index_name" + ) { + return qb + .select( arguments.selectOptions ) + .distinct() + .from( "information_schema.statistics" ) + .where( "table_schema", arguments.schemaName ) + .where( "table_name", arguments.tableName ) + .where( + "index_name", + "like", + "%#indexName#%" + ) + .get(); + } -/** - * Add permission for a specific role - * - * @query The query instance from QB - * @roleId The roleId - * @permission The permission name - * - * @return void - * */ -function addPermissionToRole( query, roleId, permission ){ - var permissionId = arguments.query - .newQuery() - .select( "permissionID" ) - .from( "cb_permission" ) - .where( "permission", arguments.permission ) - .first() - .permissionId; - arguments.query - .newQuery() - .from( "cb_rolePermissions" ) - .insert( { - "FK_roleID" : arguments.roleId, - "FK_permissionID" : permissionId - } ); -} + /** + * Drop indexes fron database + * + * @indexes The Array of indexes to delete + * @schema The schema instance from QB + * @tableName The name of table from database + * + * @return void + **/ + function dropIndexesFromSchema( + required array indexes, + required schema, + required string tableName + ) { + indexes.each( + ( index ) => { + schema.alter( + "#tableName#", + function( table ) { + table.dropConstraint( table.index( [], "#index.index_name#" ) ); + } + ); + } + ); + } -/** - * Remove permission for a specific role - * - * @query The query instance from QB - * @roleId The roleId - * @permission The permission name - * - * @return void - * */ -function removePermissionFromRole( query, roleId, permission ){ - var permissionId = arguments.query - .newQuery() - .select( "permissionID" ) - .from( "cb_permission" ) - .where( "permission", arguments.permission ) - .first() - .permissionId; - arguments.query - .newQuery() - .from( "cb_rolePermissions" ) - .where( "FK_roleID", arguments.roleId ) - .andWhere( "FK_permissionID", permissionId ) - .delete(); -} + /** + * Add permission for a specific role + * + * @query The query instance from QB + * @roleId The roleId + * @permission The permission name + * + * @return void + **/ + function addPermissionToRole( query, roleId, permission ) { + var permissionId = arguments + .query + .newQuery() + .select( "permissionID" ) + .from( "cb_permission" ) + .where( "permission", arguments.permission ) + .first().permissionId; + arguments + .query + .newQuery() + .from( "cb_rolePermissions" ) + .insert( + { + "FK_roleID" : arguments.roleId, + "FK_permissionID": permissionId + } + ); + } -/** - * Remove a permission from the system - * - * @query QB - * @permission A slug or a list of slugs or an array of permissions - */ -function removePermission( query, permission ){ - if( isSimpleValue( arguments.permission ) ){ - arguments.permission = listToArray( arguments.permission ) + /** + * Remove permission for a specific role + * + * @query The query instance from QB + * @roleId The roleId + * @permission The permission name + * + * @return void + **/ + function removePermissionFromRole( query, roleId, permission ) { + var permissionId = arguments + .query + .newQuery() + .select( "permissionID" ) + .from( "cb_permission" ) + .where( "permission", arguments.permission ) + .first().permissionId; + arguments + .query + .newQuery() + .from( "cb_rolePermissions" ) + .where( "FK_roleID", arguments.roleId ) + .andWhere( "FK_permissionID", permissionId ) + .delete(); } - arguments.query + + /** + * Remove a permission from the system + * + * @query QB + * @permission A slug or a list of slugs or an array of permissions + */ + function removePermission( query, permission ) { + if ( isSimpleValue( arguments.permission ) ) { + arguments.permission = listToArray( arguments.permission ); + } + arguments + .query .newQuery() .from( "cb_permissions" ) .whereIn( "permission", arguments.permission ) .delete(); -} + } diff --git a/modules/contentbox/models/BaseEntity.cfc b/modules/contentbox/models/BaseEntity.cfc index 998fd15f5b..cef0ed1890 100644 --- a/modules/contentbox/models/BaseEntity.cfc +++ b/modules/contentbox/models/BaseEntity.cfc @@ -5,39 +5,34 @@ * --- * This is the base class for all persistent entities */ -component - mappedsuperclass="true" - accessors ="true" - extends ="BaseEntityMethods" -{ - - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ +component mappedsuperclass="true" accessors ="true" extends ="BaseEntityMethods" { + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="createdDate" - column ="createdDate" - type ="date" - ormtype ="timestamp" - notnull ="true" - update ="false" + name="createdDate" + column="createdDate" + type="date" + ormtype="timestamp" + notnull="true" + update="false" persistent="true"; property - name ="modifiedDate" - column ="modifiedDate" - type ="date" - ormtype ="timestamp" - notnull ="true" + name="modifiedDate" + column="modifiedDate" + type="date" + ormtype="timestamp" + notnull="true" persistent=true; property - name ="isDeleted" - column ="isDeleted" - ormtype ="boolean" - notnull ="true" - default ="false" + name="isDeleted" + column="isDeleted" + ormtype="boolean" + notnull="true" + default="false" persistent="true"; -} +} \ No newline at end of file diff --git a/modules/contentbox/models/BaseEntityMethods.cfc b/modules/contentbox/models/BaseEntityMethods.cfc index a724f33759..7d1ab45c3d 100644 --- a/modules/contentbox/models/BaseEntityMethods.cfc +++ b/modules/contentbox/models/BaseEntityMethods.cfc @@ -7,72 +7,67 @@ * We created this due to the stupid bug in ACF 9-2016, where the mapped super class is not respected in table inheritance */ component { + /********************************************************************** + * ** GLOBAL DI + **********************************************************************/ - /* ********************************************************************* - ** GLOBAL DI - ********************************************************************* */ + property name="coldbox" inject="provider:coldbox" persistent="false"; - property - name ="coldbox" - inject ="provider:coldbox" - persistent="false"; - - property - name ="cachebox" - inject ="provider:cachebox" - persistent="false"; - - property - name ="interceptorService" - inject ="provider:coldbox:interceptorService" - persistent="false"; + property name="cachebox" inject="provider:cachebox" persistent="false"; property - name ="wirebox" - inject ="wirebox" + name="interceptorService" + inject="provider:coldbox:interceptorService" persistent="false"; - /* ********************************************************************* - ** CONCRETE PROPERTIES - ********************************************************************* */ + property name="wirebox" inject="wirebox" persistent="false"; + /********************************************************************** + * ** CONCRETE PROPERTIES + **********************************************************************/ // PK Pointer - this.pk = "PLEASE_SELECT_ONE"; + this.pk = "PLEASE_SELECT_ONE"; // Constraints Default this.constraints = {}; - /* ********************************************************************* - ** PUBLIC STATIC VARIABLES - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC STATIC VARIABLES + **********************************************************************/ - this.DATE_FORMAT = "mmm dd, yyyy"; + this.DATE_FORMAT = "mmm dd, yyyy"; this.DATE_FORMAT_SHORT = "mmm-dd-yyyy"; - this.TIME_FORMAT = "HH:mm:ss z"; + this.TIME_FORMAT = "HH:mm:ss z"; this.TIME_FORMAT_SHORT = "hh:mm tt"; - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ /** * Constructor */ - function init(){ + function init() { // Calculate name via md getEntityName(); - variables.createdDate = now(); + variables.createdDate = now(); variables.modifiedDate = now(); - variables.isDeleted = false; + variables.isDeleted = false; if ( isNull( this.memento.baseIncluded ) ) { // Incorporate default includes for the base class. if ( !isNull( this.memento.defaultIncludes ) ) { - this.memento.defaultIncludes.append( [ this.pk, "createdDate", "modifiedDate" ], true ); + this + .memento + .defaultIncludes + .append( [ this.pk, "createdDate", "modifiedDate"], true ); } // Incorporate default excludes for the base class. if ( !isNull( this.memento.defaultExcludes ) ) { - this.memento.defaultExcludes.append( [ "isDeleted" ], true ); + this + .memento + .defaultExcludes + .append( [ "isDeleted"], true ); } this.memento.baseIncluded = true; } @@ -83,9 +78,9 @@ component { /** * Get the entity name */ - function getEntityName(){ + function getEntityName() { if ( isNull( variables.entityName ) ) { - var md = getMetadata( this ); + var md = getMetadata( this ); variables.entityName = ( md.keyExists( "entityName" ) ? md.entityName : listLast( md.name, "." ) ); } @@ -98,10 +93,12 @@ component { * @collection The array to append * @target The target to append to: defaultIncludes, defaultExcludes, neverInclude, defaults, etc. */ - function appendToMemento( required collection, target = "defaultIncludes" ){ - var filtered = arguments.collection.filter( function( item ){ - return !arrayContainsNoCase( this.memento[ target ], arguments.item ); - } ); + function appendToMemento( required collection, target = "defaultIncludes" ) { + var filtered = arguments.collection.filter( + function( item ) { + return !arrayContainsNoCase( this.memento[ target ], arguments.item ); + } + ); this.memento[ arguments.target ].append( filtered, true ); return this; } @@ -117,10 +114,12 @@ component { required collection, required profile, target = "defaultIncludes" - ){ - var filtered = arguments.collection.filter( function( item ){ - return !arrayContainsNoCase( this.memento.profiles[ profile ][ target ], arguments.item ); - } ); + ) { + var filtered = arguments.collection.filter( + function( item ) { + return !arrayContainsNoCase( this.memento.profiles[ profile ][ target ], arguments.item ); + } + ); this.memento.profiles[ arguments.profile ][ arguments.target ].append( filtered, true ); return this; } @@ -130,14 +129,14 @@ component { * * @return The id of the object or empty value if not loaded */ - function getId(){ + function getId() { return isLoaded() ? variables[ this.pk ] : ""; } /** * pre insertion procedures */ - void function preInsert(){ + void function preInsert() { var now = now(); // prevent override of explicit stamps from imports if ( isNull( variables.createdDate ) ) { @@ -151,7 +150,7 @@ component { /** * pre update procedures */ - void function preUpdate( struct oldData ){ + void function preUpdate( struct oldData ) { variables.modifiedDate = now(); } @@ -161,14 +160,15 @@ component { * @dateFormat The date format to use, defaulted by ContentBox to mmm dd, yyyy * @timeFormat The time format to use, defaulted by ContentBox to HH:mm:ss z */ - string function getDisplayCreatedDate( dateFormat = this.DATE_FORMAT, timeFormat = this.TIME_FORMAT ){ + string function getDisplayCreatedDate( + dateFormat = this.DATE_FORMAT, + timeFormat = this.TIME_FORMAT + ) { if ( isNull( variables.createdDate ) ) { return ""; } - return dateFormat( variables.createdDate, arguments.dateFormat ) & " " & timeFormat( - variables.createdDate, - arguments.timeFormat - ); + return dateFormat( variables.createdDate, arguments.dateFormat ) & " " & timeFormat( variables.createdDate, + arguments.timeFormat ); } /** @@ -177,21 +177,22 @@ component { * @dateFormat The date format to use, defaulted by ContentBox to mmm dd, yyyy * @timeFormat The time format to use, defaulted by ContentBox to HH:mm:ss z */ - string function getDisplayModifiedDate( dateFormat = this.DATE_FORMAT, timeFormat = this.TIME_FORMAT ){ + string function getDisplayModifiedDate( + dateFormat = this.DATE_FORMAT, + timeFormat = this.TIME_FORMAT + ) { if ( isNull( variables.modifiedDate ) ) { return ""; } - return dateFormat( variables.modifiedDate, arguments.dateFormat ) & " " & timeFormat( - variables.modifiedDate, - arguments.timeFormat - ); + return dateFormat( variables.modifiedDate, arguments.dateFormat ) & " " & timeFormat( variables.modifiedDate, + arguments.timeFormat ); } /** * Verify if entity is loaded or not */ - boolean function isLoaded(){ - return ( !structKeyExists( variables, this.pk ) OR !len( variables[ this.pk ] ) ? false : true ); + boolean function isLoaded() { + return ( !structKeyExists( variables, this.pk ) || !len( variables[ this.pk ] ) ? false : true ); } /** @@ -201,50 +202,44 @@ component { * * @throws ContentHelperNotFoundException - When the passed helper is not found */ - function includeMixin( required helper ){ + function includeMixin( required helper ) { // Init the mixin location and caches reference - var defaultCache = variables.cachebox.getCache( "default" ); + var defaultCache = variables.cachebox.getCache( "default" ); var mixinLocationKey = hash( variables.coldbox.getAppHash() & arguments.helper ); var targetLocation = defaultCache.getOrSet( - // Key - "contentObjectHelper-#mixinLocationKey#", - // Producer - function(){ - var appMapping = variables.coldbox.getSetting( "AppMapping" ); - var UDFFullPath = expandPath( helper ); - var UDFRelativePath = expandPath( "/" & appMapping & "/" & helper ); + "contentObjectHelper-#mixinLocationKey#", + function() { + var appMapping = variables.coldbox.getSetting( "AppMapping" ); + var UDFFullPath = expandPath( helper ); + var UDFRelativePath = expandPath( "/" & appMapping & "/" & helper ); - // Relative Checks First - if ( fileExists( UDFRelativePath ) ) { - targetLocation = "/" & appMapping & "/" & helper; - } - // checks if no .cfc or .cfm where sent - else if ( fileExists( UDFRelativePath & ".cfc" ) ) { - targetLocation = "/" & appMapping & "/" & helper & ".cfc"; - } else if ( fileExists( UDFRelativePath & ".cfm" ) ) { - targetLocation = "/" & appMapping & "/" & helper & ".cfm"; - } else if ( fileExists( UDFFullPath ) ) { - targetLocation = "#helper#"; - } else if ( fileExists( UDFFullPath & ".cfc" ) ) { - targetLocation = "#helper#.cfc"; - } else if ( fileExists( UDFFullPath & ".cfm" ) ) { - targetLocation = "#helper#.cfm"; - } else { - throw( - message = "Error loading content helper: #helper#", - detail = "Please make sure you verify the file location.", - type = "ContentHelperNotFoundException" - ); - } - return targetLocation; - }, - // Timeout: 1 week - 10080 - ); + if ( fileExists( UDFRelativePath ) ) { + targetLocation = "/" & appMapping & "/" & helper; + } else if ( fileExists( UDFRelativePath & ".cfc" ) ) { + targetLocation = "/" & appMapping & "/" & helper & ".cfc"; + } else if ( fileExists( UDFRelativePath & ".cfm" ) ) { + targetLocation = "/" & appMapping & "/" & helper & ".cfm"; + } else if ( fileExists( UDFFullPath ) ) { + targetLocation = "#helper#"; + } else if ( fileExists( UDFFullPath & ".cfc" ) ) { + targetLocation = "#helper#.cfc"; + } else if ( fileExists( UDFFullPath & ".cfm" ) ) { + targetLocation = "#helper#.cfm"; + } else { + throw( + message = "Error loading content helper: #helper#", + detail = "Please make sure you verify the file location.", + type = "ContentHelperNotFoundException" + ); + } + return targetLocation; + }, + 10080 + ); // Include the helper - include targetLocation; + include "#targetLocation#"; return this; } @@ -256,8 +251,8 @@ component { * * @return An array */ - private array function arrayWrap( required items ){ + private array function arrayWrap( required items ) { return isArray( arguments.items ) ? arguments.items : listToArray( arguments.items ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/comments/Comment.cfc b/modules/contentbox/models/comments/Comment.cfc index 9f286d7602..46a7a33167 100755 --- a/modules/contentbox/models/comments/Comment.cfc +++ b/modules/contentbox/models/comments/Comment.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -14,87 +14,75 @@ component cachename ="cbComment" cacheuse ="read-write" { - - /* ********************************************************************* - ** DI - ********************************************************************* */ + /********************************************************************** + * ** DI + **********************************************************************/ property - name ="markdown" - inject ="provider:Processor@cbmarkdown" + name="markdown" + inject="provider:Processor@cbmarkdown" persistent="false"; - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="commentID" - column ="commentID" + name="commentID" + column="commentID" fieldtype="id" generator="uuid" - length ="36" - ormtype ="string" - update ="false"; + length="36" + ormtype="string" + update="false"; - property - name ="content" - ormtype="text" - notnull="true"; + property name="content" ormtype="text" notnull="true"; - property - name ="author" - length ="100" - notnull="true"; + property name="author" length="100" notnull="true"; - property - name ="authorIP" - column ="authorIP" - length ="100" - notnull="true"; + property name="authorIP" column="authorIP" length="100" notnull="true"; property - name ="authorEmail" - column ="authorEmail" - length ="255" + name="authorEmail" + column="authorEmail" + length="255" notnull="true"; property - name ="authorURL" - column ="authorURL" - length ="255" + name="authorURL" + column="authorURL" + length="255" notnull="false"; property - name ="isApproved" - column ="isApproved" + name="isApproved" + column="isApproved" notnull="true" ormtype="boolean" default="false" - index ="idx_contentComment,idx_approved"; + index="idx_contentComment,idx_approved"; - /* ********************************************************************* - ** RELATIONSHIPS - ********************************************************************* */ + /********************************************************************** + * ** RELATIONSHIPS + **********************************************************************/ // M20 -> Content loaded as a proxy property - name ="relatedContent" - notnull ="true" - cfc ="contentbox.models.content.BaseContent" + name="relatedContent" + notnull="true" + cfc="contentbox.models.content.BaseContent" fieldtype="many-to-one" - fkcolumn ="FK_contentID" - lazy ="true" - index ="idx_contentComment"; - - /* ********************************************************************* - ** CONSTRAINTS + PK - ********************************************************************* */ + fkcolumn="FK_contentID" + lazy="true" + index="idx_contentComment"; + /********************************************************************** + * ** CONSTRAINTS + PK + **********************************************************************/ this.pk = "commentID"; this.memento = { - defaultIncludes : [ + defaultIncludes: [ "content", "displayContent:renderedContent", "author", @@ -103,21 +91,21 @@ component "authorURL", "isApproved" ], - defaultExcludes : [ "relatedContent" ] + defaultExcludes: [ "relatedContent"] }; this.constraints = { - "content" : { required : true }, - "author" : { required : true, size : "1..100" }, - "authorIP" : { required : true, size : "1..100" }, - "authorEmail" : { required : true, size : "1..255", type : "email" }, - "authorURL" : { required : true, size : "1..255", type : "URL" }, - "isApproved" : { required : true, type : "boolean" }, - "relatedContent" : { required : true } + "content" : { required: true }, + "author" : { required: true, size: "1..100" }, + "authorIP" : { required: true, size: "1..100" }, + "authorEmail" : { required: true, size: "1..255", type: "email" }, + "authorURL" : { required: true, size: "1..255", type: "URL" }, + "isApproved" : { required: true, type: "boolean" }, + "relatedContent": { required: true } }; - function init(){ - variables.isApproved = false; + function init() { + variables.isApproved = false; variables.createdDate = now(); super.init(); @@ -128,7 +116,7 @@ component /** * Build a snapshot of the related content */ - struct function getRelatedContentSnapshot(){ + struct function getRelatedContentSnapshot() { if ( hasRelatedContent() ) { return getRelatedContent().getInfoSnapshot(); } @@ -138,14 +126,20 @@ component /** * Render the comment using markdown and encoding it for HTML output */ - string function getDisplayContent(){ - return variables.markdown.toHTML( getContent().reReplace( "##{1,6}\s", "", "all" ) ); + string function getDisplayContent() { + return variables.markdown.toHTML( + getContent().reReplace( + "##{1,6}\s", + "", + "all" + ) + ); } /** * Get parent slug from either the page it belongs or the entry it belongs to. */ - function getParentSlug(){ + function getParentSlug() { if ( hasRelatedContent() ) { return getRelatedContent().getSlug(); } @@ -155,11 +149,11 @@ component /** * Get parent title from either the page it belongs or the entry it belongs to. */ - function getParentTitle(){ + function getParentTitle() { if ( hasRelatedContent() ) { return getRelatedContent().getTitle(); } return ""; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/comments/CommentService.cfc b/modules/contentbox/models/comments/CommentService.cfc index e8764fc26b..83e6759577 100755 --- a/modules/contentbox/models/comments/CommentService.cfc +++ b/modules/contentbox/models/comments/CommentService.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -6,20 +6,25 @@ * Service to handle comment operations. */ component extends="cborm.models.VirtualEntityService" singleton { - // DI property name="mailService" inject="mailService@cbmailservices"; + property name="renderer" inject="coldbox:renderer"; + property name="settingService" inject="id:settingService@contentbox"; + property name="securityService" inject="id:securityService@contentbox"; + property name="CBHelper" inject="id:CBHelper@contentbox"; + property name="log" inject="logbox:logger:{this}"; + property name="interceptorService" inject="coldbox:interceptorService"; /** * Constructor */ - CommentService function init(){ + CommentService function init() { super.init( entityName = "cbComment", useQueryCaching = "true" ); return this; } @@ -30,12 +35,15 @@ component extends="cborm.models.VirtualEntityService" singleton { * @contentId The content id to filter on * @isApproved If passed, use it to filter on */ - numeric function getTotalCountByContent( string contentId = "", boolean isApproved ){ + numeric function getTotalCountByContent( string contentId = "", boolean isApproved ) { return newCriteria() .isEq( "relatedContent.contentID", arguments.contentId ) - .when( !isNull( arguments.isApproved ), function( c ){ - c.isEq( "isApproved", javacast( "Boolean", isApproved ) ); - } ) + .when( + !isNull( arguments.isApproved ), + function( c ) { + c.isEq( "isApproved", javacast( "Boolean", isApproved ) ); + } + ) .count(); } @@ -44,12 +52,13 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @siteID The site to filter on */ - numeric function getTotalCount( string siteID = "" ){ - return newCriteria() - .when( len( arguments.siteID ), function( c ){ - c.joinTo( "relatedContent", "relatedContent" ).isEq( "relatedContent.site.siteID", siteID ); - } ) - .count(); + numeric function getTotalCount( string siteID = "" ) { + return newCriteria().when( + len( arguments.siteID ), + function( c ) { + c.joinTo( "relatedContent", "relatedContent" ).isEq( "relatedContent.site.siteID", siteID ); + } + ).count(); } /** @@ -57,12 +66,15 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @siteID The site to filter on */ - numeric function getApprovedCount( string siteID = "" ){ + numeric function getApprovedCount( string siteID = "" ) { return newCriteria() .isTrue( "isApproved" ) - .when( len( arguments.siteID ), function( c ){ - c.joinTo( "relatedContent", "relatedContent" ).isEq( "relatedContent.site.siteID", siteID ); - } ) + .when( + len( arguments.siteID ), + function( c ) { + c.joinTo( "relatedContent", "relatedContent" ).isEq( "relatedContent.site.siteID", siteID ); + } + ) .count(); } @@ -71,12 +83,15 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @siteID The site to filter on */ - numeric function getUnApprovedCount( string siteID = "" ){ + numeric function getUnApprovedCount( string siteID = "" ) { return newCriteria() .isFalse( "isApproved" ) - .when( len( arguments.siteID ), function( c ){ - c.joinTo( "relatedContent", "relatedContent" ).isEq( "relatedContent.site.siteID", siteID ); - } ) + .when( + len( arguments.siteID ), + function( c ) { + c.joinTo( "relatedContent", "relatedContent" ).isEq( "relatedContent.site.siteID", siteID ); + } + ) .count(); } @@ -99,32 +114,44 @@ component extends="cborm.models.VirtualEntityService" singleton { offset = 0, string sortOrder = "desc", string siteID = "" - ){ - var results = { "count" : 0, "comments" : [] }; - var c = newCriteria() - // only approved comments + ) { + var results = { "count": 0, "comments": [] }; + var c = newCriteria() .isTrue( "isApproved" ) + .when( + !isNull( arguments.contentID ) && len( arguments.contentID ), + function( c ) { + c.isEq( "relatedContent.contentID", contentID ); + } + ) + .when( + !isNull( arguments.contentType ) && len( arguments.contentType ), + function( c ) { + c.createCriteria( "relatedContent" ).isEq( "class", contentType ); + } + ) + // only approved comments + // By Content? - .when( !isNull( arguments.contentID ) AND len( arguments.contentID ), function( c ){ - c.isEq( "relatedContent.contentID", contentID ); - } ) + // By Content Type Discriminator: class is a special hibernate deal - .when( !isNull( arguments.contentType ) AND len( arguments.contentType ), function( c ){ - c.createCriteria( "relatedContent" ).isEq( "class", contentType ); - } ) + // Site Filter - .when( len( arguments.siteID ), function( c ){ - c.joinTo( "relatedContent", "relatedContent" ).isEq( "relatedContent.site.siteID", siteID ); - } ); + .when( + len( arguments.siteID ), + function( c ) { + c.joinTo( "relatedContent", "relatedContent" ).isEq( "relatedContent.site.siteID", siteID ); + } + ); // run criteria query and projections count - results.count = c.count(); + results.count = c.count(); results.comments = c.list( - offset : arguments.offset, - max : arguments.max, - sortOrder: "createdDate #arguments.sortOrder#", - asQuery : false - ); + offset = arguments.offset, + max = arguments.max, + sortOrder = "createdDate #arguments.sortOrder#", + asQuery = false + ); return results; } @@ -134,13 +161,17 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @expirationDays Required level of staleness in days to delete (0=all unapproved) */ - CommentService function deleteUnApproved( numeric expirationDays = 0 ){ + CommentService function deleteUnApproved( numeric expirationDays = 0 ) { var hqlQuery = "from cbComment where isApproved = :approved"; - var params = { "approved" : false }; + var params = { "approved": false }; // if we have an expirationDays setting greater than 0, add it to query for our date filter if ( arguments.expirationDays ) { - var expirationDate = dateAdd( "d", -arguments.expirationDays, now() ); + var expirationDate = dateAdd( + "d", + -arguments.expirationDays, + now() + ); hqlQuery &= " and createdDate < :expiration"; params[ "expiration" ] = expirationDate; } @@ -158,16 +189,14 @@ component extends="cborm.models.VirtualEntityService" singleton { * @loggedInUser The current logged in user making the comment. If no logged in User, this is a non-persisted entity * @result Return a struct of : { moderated:boolean, messages : array } */ - struct function saveComment( required comment, required loggedInUser ){ + struct function saveComment( required comment, required loggedInUser ) { transaction { // Comment reference - var inComment = arguments.comment; + var inComment = arguments.comment; // get site settings - var siteSettings = variables.settingService.getAllSiteSettings( - siteSlug: inComment.getRelatedContent().getSiteSlug() - ); + var siteSettings = variables.settingService.getAllSiteSettings( siteSlug = inComment.getRelatedContent().getSiteSlug() ); // results - var results = { "moderated" : true, "messages" : [] }; + var results = { "moderated": true, "messages": [] }; // Log the IP Address inComment.setAuthorIP( variables.securityService.getRealIP() ); @@ -176,9 +205,8 @@ component extends="cborm.models.VirtualEntityService" singleton { // Run moderation rules if not logged in. if ( - arguments.loggedInUser.isLoggedIn() - OR - runModerationRules( comment = inComment, settings = siteSettings ) + arguments.loggedInUser.isLoggedIn() || + runModerationRules( comment = inComment, settings = siteSettings ) ) { // send for saving, finally phew! save( inComment ); @@ -213,16 +241,16 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @comment The comment object */ - public void function sendSubscriptionNotifications( required any comment ){ - var content = arguments.comment.getRelatedContent(); + public void function sendSubscriptionNotifications( required any comment ) { + var content = arguments.comment.getRelatedContent(); // get subscribers for this content item - var subscriptions = content.getCommentSubscriptions(); - var settings = variables.settingService.getAllSettings(); + var subscriptions = content.getCommentSubscriptions(); + var settings = variables.settingService.getAllSettings(); var commentAuthorEmail = arguments.comment.getAuthorEmail(); // get body tokens; can reuse most for all emails - var bodyTokens = arguments.comment.getMemento(); - bodyTokens[ "contentURL" ] = CBHelper.linkContent( content ); + var bodyTokens = arguments.comment.getMemento(); + bodyTokens[ "contentURL" ] = CBHelper.linkContent( content ); bodyTokens[ "contentTitle" ] = arguments.comment.getParentTitle(); // loop over subscribers @@ -236,27 +264,27 @@ component extends="cborm.models.VirtualEntityService" singleton { // Send it baby! var mail = variables.mailService.newMail( - to = subscriber.getSubscriberEmail(), - from = settings.cb_site_outgoingEmail, - subject = "New comment was added", - bodyTokens = bodyTokens, - type = "html", - server = settings.cb_site_mail_server, - username = settings.cb_site_mail_username, - password = settings.cb_site_mail_password, - port = settings.cb_site_mail_smtp, - useTLS = settings.cb_site_mail_tls, - useSSL = settings.cb_site_mail_ssl - ); + to = subscriber.getSubscriberEmail(), + from = settings.cb_site_outgoingEmail, + subject = "New comment was added", + bodyTokens = bodyTokens, + type = "html", + server = settings.cb_site_mail_server, + username = settings.cb_site_mail_username, + password = settings.cb_site_mail_password, + port = settings.cb_site_mail_smtp, + useTLS = settings.cb_site_mail_tls, + useSSL = settings.cb_site_mail_ssl + ); // generate content for email from template mail.setBody( - variables.renderer.layout( - view = "/contentbox/email_templates/comment_notification", - layout = "/contentbox/email_templates/layouts/email", - args = { gravatarEmail : commentAuthorEmail } - ) - ); + variables.renderer.layout( + view = "/contentbox/email_templates/comment_notification", + layout = "/contentbox/email_templates/layouts/email", + args = { gravatarEmail: commentAuthorEmail } + ) + ); // send it out variables.mailService.send( mail ); @@ -264,6 +292,98 @@ component extends="cborm.models.VirtualEntityService" singleton { } } + /** + * comment search returns struct with keys [comments,count] + * + * @search Search query + * @isApproved approved bit + * @contentID matching content id + * @max max records + * @offset offset for pagination + * @sortOrder The sort order, defaults to `createdDate DESC` + * @siteID The site to filter on if needed + * + * @return struct with { comments, count } + */ + struct function search( + search = "", + isApproved, + contentID, + numeric max = 0, + numeric offset = 0, + sortOrder = "createdDate DESC", + string siteID = "" + ) { + var results = { "count": 0, "comments": [] }; + var c = newCriteria(); + + // isApproved filter + if ( !isNull( arguments.isApproved ) && arguments.isApproved NEQ "any" ) { + c.isEq( "isApproved", javacast( "boolean", arguments.isApproved ) ); + } + + // Content Filter + if ( !isNull( arguments.contentID ) && arguments.contentID NEQ "all" ) { + c.isEq( "relatedContent.contentID", arguments.contentID ); + } + + // Search Criteria + if ( len( arguments.search ) ) { + // OR disjunction on author, authorEmail and content. + c.$or( + c.restrictions.like( "author", "%#arguments.search#%" ), + c.restrictions.like( "authorEmail", "%#arguments.search#%" ), + c.restrictions.like( "content", "%#arguments.search#%" ) + ); + } + + // Site Filter + if ( len( arguments.siteID ) ) { + c.joinTo( "relatedContent", "relatedContent" ).isEq( "relatedContent.site.siteID", arguments.siteID ); + } + + // run criteria query and projections count + results.count = c.count(); + results.comments = c.list( + offset = arguments.offset, + max = arguments.max, + sortOrder = arguments.sortOrder, + asQuery = false + ); + + return results; + } + + /** + * Bulk Updates + * + * @commentID The list or array of ID's to bulk update + * @status The status either 'approve' or 'moderate' + * + * @return CommentService + */ + any function bulkStatus( any commentID, status = "" ) { + var approve = false; + + // approve flag + if ( arguments.status EQ "approve" ) { + approve = true; + } + + // Get all by id + var comments = getAll( id = arguments.commentID ).map( + function( thisComment ) { + thisComment.setIsApproved( approve ); + return thisComment; + } + ); + + // transaction the save of all the comments + saveAll( comments ); + + return this; + } + /** * Run moderation rules on an incoming comment and set of contentbox settings. If this method returns a false then the comment is moderated * and can continue to be saved. If returns false, then it is blocked and must NOT be saved. @@ -271,32 +391,31 @@ component extends="cborm.models.VirtualEntityService" singleton { * @comment Comment to moderate check * @settings The contentbox settings to moderate against */ - private boolean function runModerationRules( required comment, required settings ){ + private boolean function runModerationRules( required comment, required settings ) { // Comment reference - var inComment = arguments.comment; + var inComment = arguments.comment; var inSettings = arguments.settings; - var allowSave = true; + var allowSave = true; // Not moderation, just approve and return - if ( NOT settings.cb_comments_moderation ) { + if ( !settings.cb_comments_moderation ) { inComment.setIsApproved( true ); return true; } - // Check if user has already an approved comment. If they do, then approve them // cfformat-ignore-start - if ( inSettings.cb_comments_moderation_whitelist AND userHasPreviousAcceptedComment( inComment.getAuthorEmail() ) ) { - inComment.setIsApproved( true ); - return true; - } + if ( +inSettings.cb_comments_moderation_whitelist && userHasPreviousAcceptedComment( inComment.getAuthorEmail() ) +) { +inComment.setIsApproved( true ); +return true; +} // cfformat-ignore-end // Execute moderation queries if ( - len( inSettings.cb_comments_moderation_blacklist ) AND anyKeywordMatch( - inComment, - inSettings.cb_comments_moderation_blacklist - ) + len( inSettings.cb_comments_moderation_blacklist ) && + anyKeywordMatch( inComment, inSettings.cb_comments_moderation_blacklist ) ) { inComment.setIsApproved( false ); allowSave = true; @@ -304,10 +423,8 @@ component extends="cborm.models.VirtualEntityService" singleton { // Execute blocking queries if ( - len( inSettings.cb_comments_moderation_blockedlist ) AND anyKeywordMatch( - inComment, - inSettings.cb_comments_moderation_blockedlist - ) + len( inSettings.cb_comments_moderation_blockedlist ) && + anyKeywordMatch( inComment, inSettings.cb_comments_moderation_blockedlist ) ) { inComment.setIsApproved( false ); allowSave = false; @@ -315,9 +432,9 @@ component extends="cborm.models.VirtualEntityService" singleton { // announce it. var iData = { - comment : arguments.comment, - settings : arguments.settings, - allowSave : allowSave + comment : arguments.comment, + settings : arguments.settings, + allowSave: allowSave }; interceptorService.announce( "cbui_onCommentModerationRules", iData ); @@ -328,17 +445,17 @@ component extends="cborm.models.VirtualEntityService" singleton { /** * Regex matching of a list of entries against a comment and matching keyword list */ - private boolean function anyKeywordMatch( comment, matchList ){ + private boolean function anyKeywordMatch( comment, matchList ) { var inComment = arguments.comment; - var del = chr( 13 ) & chr( 10 ); - var inList = listToArray( arguments.matchList, del ); + var del = chr( 13 ) & chr( 10 ); + var inList = listToArray( arguments.matchList, del ); - for ( var x = 1; x lte arrayLen( inList ); x++ ) { + for ( var x = 1; x LTE arrayLen( inList ); x++ ) { // Verify each keword via regex if ( - reFindNoCase( inList[ x ], inComment.getContent() ) OR - reFindNoCase( inList[ x ], inComment.getAuthor() ) OR - reFindNoCase( inList[ x ], inComment.getAuthorIP() ) + reFindNoCase( inList[ x ], inComment.getContent() ) || + reFindNoCase( inList[ x ], inComment.getAuthor() ) || + reFindNoCase( inList[ x ], inComment.getAuthorIP() ) ) { return true; } @@ -352,8 +469,8 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @email The email address to check. */ - private boolean function userHasPreviousAcceptedComment( required email ){ - var args = { "authorEmail" : arguments.email, "isApproved" : true }; + private boolean function userHasPreviousAcceptedComment( required email ) { + var args = { "authorEmail": arguments.email, "isApproved": true }; return ( countWhere( argumentCollection = args ) GT 0 ); } @@ -363,14 +480,14 @@ component extends="cborm.models.VirtualEntityService" singleton { * @comment Comment to moderate check * @siteSettings The contentbox site settings to moderate against */ - private void function sendNotificationEmails( required comment, required siteSettings ){ + private void function sendNotificationEmails( required comment, required siteSettings ) { // Comment reference var inComment = arguments.comment; - var settings = variables.settingService.getAllSettings(); - var site = inComment.getRelatedContent().getSite(); + var settings = variables.settingService.getAllSettings(); + var site = inComment.getRelatedContent().getSite(); var outEmails = settings.cb_site_email; - var subject = ""; - var template = ""; + var subject = ""; + var template = ""; // Verify if we have active notifications, else just quit notification process if ( !arguments.siteSettings.cb_comments_notify ) { @@ -384,143 +501,53 @@ component extends="cborm.models.VirtualEntityService" singleton { } // get mail payload - var bodyTokens = inComment.getMemento(); - bodyTokens[ "whoisURL" ] = settings.cb_comments_whoisURL; + var bodyTokens = inComment.getMemento(); + bodyTokens[ "whoisURL" ] = settings.cb_comments_whoisURL; bodyTokens[ "commentURL" ] = CBHelper.linkComment( comment = inComment, ssl = site.getIsSSL() ); - bodyTokens[ "deleteURL" ] = CBHelper.linkAdmin( event = "comments.moderate", ssl = settings.cb_admin_ssl ) & "?commentID=#inComment.getCommentID()#"; - bodyTokens[ "approveURL" ] = CBHelper.linkAdmin( event = "comments.moderate", ssl = settings.cb_admin_ssl ) & "?commentID=#inComment.getCommentID()#"; - bodyTokens[ "contentURL" ] = CBHelper.linkContent( - content = inComment.getRelatedContent(), - ssl = site.getIsSSL() - ); + bodyTokens[ "deleteURL" ] = CBHelper.linkAdmin( event = "comments.moderate", + ssl = settings.cb_admin_ssl ) & "?commentID=#inComment.getCommentID()#"; + bodyTokens[ "approveURL" ] = CBHelper.linkAdmin( event = "comments.moderate", + ssl = settings.cb_admin_ssl ) & "?commentID=#inComment.getCommentID()#"; + bodyTokens[ "contentURL" ] = CBHelper.linkContent( content = inComment.getRelatedContent(), + ssl = site.getIsSSL() ); bodyTokens[ "contentTitle" ] = inComment.getParentTitle(); // Moderation Email? Comment is moderated? - if ( inComment.getIsApproved() eq false AND arguments.siteSettings.cb_comments_moderation_notify ) { - subject = "New comment needs moderation on post: #bodyTokens.contentTitle#"; + if ( inComment.getIsApproved() EQ false && arguments.siteSettings.cb_comments_moderation_notify ) { + subject = "New comment needs moderation on post: #bodyTokens.contentTitle#"; template = "comment_moderation"; } else { // Else, new comment notification - subject = "New comment on post: #bodyTokens.contentTitle#"; + subject = "New comment on post: #bodyTokens.contentTitle#"; template = "comment_new"; } // Send it baby! var mail = variables.mailservice.newMail( - to = outEmails, - from = settings.cb_site_outgoingEmail, - subject = subject, - bodyTokens = bodyTokens, - type = "html", - server = settings.cb_site_mail_server, - username = settings.cb_site_mail_username, - password = settings.cb_site_mail_password, - port = settings.cb_site_mail_smtp, - useTLS = settings.cb_site_mail_tls, - useSSL = settings.cb_site_mail_ssl - ); + to = outEmails, + from = settings.cb_site_outgoingEmail, + subject = subject, + bodyTokens = bodyTokens, + type = "html", + server = settings.cb_site_mail_server, + username = settings.cb_site_mail_username, + password = settings.cb_site_mail_password, + port = settings.cb_site_mail_smtp, + useTLS = settings.cb_site_mail_tls, + useSSL = settings.cb_site_mail_ssl + ); // generate content for email from template mail.setBody( - renderer.layout( - view = "/contentbox/email_templates/#template#", - layout = "/contentbox/email_templates/layouts/email", - args = { gravatarEmail : inComment.getAuthorEmail() } - ) - ); + renderer.layout( + view = "/contentbox/email_templates/#template#", + layout = "/contentbox/email_templates/layouts/email", + args = { gravatarEmail: inComment.getAuthorEmail() } + ) + ); // send it out variables.mailService.send( mail ); } - /** - * comment search returns struct with keys [comments,count] - * - * @search Search query - * @isApproved approved bit - * @contentID matching content id - * @max max records - * @offset offset for pagination - * @sortOrder The sort order, defaults to `createdDate DESC` - * @siteID The site to filter on if needed - * - * @return struct with { comments, count } - */ - struct function search( - search = "", - isApproved, - contentID, - numeric max = 0, - numeric offset = 0, - sortOrder = "createdDate DESC", - string siteID = "" - ){ - var results = { "count" : 0, "comments" : [] }; - var c = newCriteria(); - - // isApproved filter - if ( !isNull( arguments.isApproved ) AND arguments.isApproved NEQ "any" ) { - c.isEq( "isApproved", javacast( "boolean", arguments.isApproved ) ); - } - - // Content Filter - if ( !isNull( arguments.contentID ) AND arguments.contentID NEQ "all" ) { - c.isEq( "relatedContent.contentID", arguments.contentID ); - } - - // Search Criteria - if ( len( arguments.search ) ) { - // OR disjunction on author, authorEmail and content. - c.$or( - c.restrictions.like( "author", "%#arguments.search#%" ), - c.restrictions.like( "authorEmail", "%#arguments.search#%" ), - c.restrictions.like( "content", "%#arguments.search#%" ) - ); - } - - // Site Filter - if ( len( arguments.siteID ) ) { - c.joinTo( "relatedContent", "relatedContent" ).isEq( "relatedContent.site.siteID", arguments.siteID ); - } - - // run criteria query and projections count - results.count = c.count(); - results.comments = c.list( - offset = arguments.offset, - max = arguments.max, - sortOrder = arguments.sortOrder, - asQuery = false - ); - - return results; - } - - /** - * Bulk Updates - * - * @commentID The list or array of ID's to bulk update - * @status The status either 'approve' or 'moderate' - * - * @return CommentService - */ - any function bulkStatus( any commentID, status = "" ){ - var approve = false; - - // approve flag - if ( arguments.status eq "approve" ) { - approve = true; - } - - // Get all by id - var comments = getAll( id = arguments.commentID ).map( function( thisComment ){ - thisComment.setIsApproved( approve ); - return thisComment; - } ); - - // transaction the save of all the comments - saveAll( comments ); - - return this; - } - -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/BaseContent.cfc b/modules/contentbox/models/content/BaseContent.cfc index 63564f7cc3..bbbb2075d2 100644 --- a/modules/contentbox/models/content/BaseContent.cfc +++ b/modules/contentbox/models/content/BaseContent.cfc @@ -15,7 +15,6 @@ component cacheuse ="read-write" discriminatorColumn="contentType" { - /** * -------------------------------------------------------------------------- * DI @@ -24,48 +23,55 @@ component */ property - name ="categoryService" - inject ="provider:categoryService@contentbox" + name="categoryService" + inject="provider:categoryService@contentbox" persistent="false"; property - name ="contentService" - inject ="provider:contentService@contentbox" + name="contentService" + inject="provider:contentService@contentbox" persistent="false"; property - name ="contentVersionService" - inject ="provider:contentVersionService@contentbox" + name="contentVersionService" + inject="provider:contentVersionService@contentbox" persistent="false"; property - name ="contentTemplateService" - inject ="provider:ContentTemplateService@contentbox" + name="contentTemplateService" + inject="provider:ContentTemplateService@contentbox" persistent="false"; property - name ="customFieldService" - inject ="provider:customFieldService@contentbox" + name="commentService" + inject="provider:commentService@contentbox" persistent="false"; property - name ="i18n" - inject ="provider:i18n@cbi18n" + name="customFieldService" + inject="provider:customFieldService@contentbox" + persistent="false"; + + property name="i18n" inject="provider:i18n@cbi18n" persistent="false"; + + property + name="JSONPrettyPrint" + inject="provider:JSONPrettyPrint@JSONPrettyPrint" persistent="false"; property - name ="JSONPrettyPrint" - inject ="provider:JSONPrettyPrint@JSONPrettyPrint" + name="settingService" + inject="provider:settingService@contentbox" persistent="false"; property - name ="settingService" - inject ="provider:settingService@contentbox" + name="mediaService" + inject="provider:MediaService@contentbox" persistent="false"; property - name ="mediaService" - inject ="provider:MediaService@contentbox" + name="statsService" + inject="provider:statsService@contentbox" persistent="false"; /** @@ -74,10 +80,7 @@ component * -------------------------------------------------------------------------- */ - property - name ="renderedContent" - persistent="false" - default =""; + property name="renderedContent" persistent="false" default=""; /** * -------------------------------------------------------------------------- @@ -88,23 +91,23 @@ component */ property - name ="createdDate" - column ="createdDate" - type ="date" + name="createdDate" + column="createdDate" + type="date" ormtype="timestamp" notnull="true" - update ="false"; + update="false"; property - name ="modifiedDate" - column ="modifiedDate" - type ="date" + name="modifiedDate" + column="modifiedDate" + type="date" ormtype="timestamp" notnull="true"; property - name ="isDeleted" - column ="isDeleted" + name="isDeleted" + column="isDeleted" ormtype="boolean" notnull="true" default="false"; @@ -116,141 +119,141 @@ component */ property - name ="contentID" - column ="contentID" + name="contentID" + column="contentID" fieldtype="id" generator="uuid" - length ="36" - ormtype ="string" - update ="false"; + length="36" + ormtype="string" + update="false"; property - name ="contentType" - column ="contentType" - setter ="false" - update ="false" - insert ="false" - index ="idx_discriminator,idx_published" + name="contentType" + column="contentType" + setter="false" + update="false" + insert="false" + index="idx_discriminator,idx_published" default=""; property - name ="title" - column ="title" + name="title" + column="title" notnull="true" - length ="500" + length="500" default="" - index ="idx_search"; + index="idx_search"; property - name ="slug" - column ="slug" + name="slug" + column="slug" notnull="true" - length ="500" + length="500" default="" - index ="idx_slug,idx_publishedSlug"; + index="idx_slug,idx_publishedSlug"; property - name ="publishedDate" - column ="publishedDate" + name="publishedDate" + column="publishedDate" notnull="false" ormtype="timestamp" - index ="idx_publishedDate"; + index="idx_publishedDate"; property - name ="expireDate" - column ="expireDate" + name="expireDate" + column="expireDate" notnull="false" ormtype="timestamp" - index ="idx_expireDate"; + index="idx_expireDate"; property - name ="isPublished" - column ="isPublished" + name="isPublished" + column="isPublished" notnull="true" ormtype="boolean" default="true" - index ="idx_published,idx_search,idx_publishedSlug"; + index="idx_published,idx_search,idx_publishedSlug"; property - name ="allowComments" - column ="allowComments" + name="allowComments" + column="allowComments" notnull="true" ormtype="boolean" default="true"; property - name ="passwordProtection" - column ="passwordProtection" + name="passwordProtection" + column="passwordProtection" notnull="false" - length ="100" + length="100" default=""; property - name ="HTMLKeywords" - column ="HTMLKeywords" + name="HTMLKeywords" + column="HTMLKeywords" notnull="false" - length ="160" + length="160" default=""; property - name ="HTMLDescription" - column ="HTMLDescription" + name="HTMLDescription" + column="HTMLDescription" notnull="false" - length ="160" + length="160" default=""; property - name ="HTMLTitle" - column ="HTMLTitle" + name="HTMLTitle" + column="HTMLTitle" notnull="false" - length ="255" + length="255" default=""; property - name ="cache" - column ="cache" + name="cache" + column="cache" notnull="true" ormtype="boolean" default="true" - index ="idx_cache"; + index="idx_cache"; property - name ="cacheTimeout" - column ="cacheTimeout" + name="cacheTimeout" + column="cacheTimeout" notnull="false" ormtype="integer" default="0" - index ="idx_cachetimeout"; + index="idx_cachetimeout"; property - name ="cacheLastAccessTimeout" - column ="cacheLastAccessTimeout" + name="cacheLastAccessTimeout" + column="cacheLastAccessTimeout" notnull="false" ormtype="integer" default="0" - index ="idx_cachelastaccesstimeout"; + index="idx_cachelastaccesstimeout"; property - name ="markup" - column ="markup" + name="markup" + column="markup" notnull="true" - length ="100" + length="100" default="HTML"; property - name ="showInSearch" - column ="showInSearch" + name="showInSearch" + column="showInSearch" notnull="true" ormtype="boolean" default="true" - index ="idx_showInSearch"; + index="idx_showInSearch"; property - name ="featuredImage" - column ="featuredImage" + name="featuredImage" + column="featuredImage" notnull="false" default="" - length ="500"; + length="500"; /** * -------------------------------------------------------------------------- @@ -260,162 +263,156 @@ component // M20 -> creator loaded as a proxy and fetched immediately property - name ="creator" - notnull ="true" - cfc ="contentbox.models.security.Author" + name="creator" + notnull="true" + cfc="contentbox.models.security.Author" fieldtype="many-to-one" - fkcolumn ="FK_authorID" - lazy ="true"; + fkcolumn="FK_authorID" + lazy="true"; // M20 -> site loaded as a proxy and fetched immediately property - name ="site" - notnull ="true" - cfc ="contentbox.models.system.Site" + name="site" + notnull="true" + cfc="contentbox.models.system.Site" fieldtype="many-to-one" - fkcolumn ="FK_siteID" - fetch ="join"; + fkcolumn="FK_siteID" + lazy="true"; // O2M -> Comments property - name ="comments" + name="comments" singularName="comment" - fieldtype ="one-to-many" - type ="array" - lazy ="true" - batchsize ="25" - orderby ="createdDate" - cfc ="contentbox.models.comments.Comment" - fkcolumn ="FK_contentID" - inverse ="true" - cascade ="all-delete-orphan"; + fieldtype="one-to-many" + type="array" + lazy="true" + batchsize="25" + orderby="createdDate" + cfc="contentbox.models.comments.Comment" + fkcolumn="FK_contentID" + inverse="true" + cascade="all-delete-orphan"; // O2M -> CustomFields property - name ="customFields" + name="customFields" singularName="customField" - fieldtype ="one-to-many" - type ="array" - lazy ="extra" - batchsize ="25" - cfc ="contentbox.models.content.CustomField" - fkcolumn ="FK_contentID" - inverse ="true" - cascade ="all-delete-orphan"; + fieldtype="one-to-many" + type="array" + lazy="extra" + batchsize="25" + cfc="contentbox.models.content.CustomField" + fkcolumn="FK_contentID" + inverse="true" + cascade="all-delete-orphan"; // O2M -> ContentVersions property - name ="contentVersions" + name="contentVersions" singularName="contentVersion" - fieldtype ="one-to-many" - type ="array" - lazy ="extra" - batchsize ="25" - cfc ="contentbox.models.content.ContentVersion" - orderby ="version desc" - fkcolumn ="FK_contentID" - inverse ="true" - cascade ="all-delete-orphan"; + fieldtype="one-to-many" + type="array" + lazy="extra" + batchsize="25" + cfc="contentbox.models.content.ContentVersion" + orderby="version desc" + fkcolumn="FK_contentID" + inverse="true" + cascade="all-delete-orphan"; property name="activeContentVersions" persistent="false"; // M20 -> Parent Page loaded as a proxy property - name ="parent" - cfc ="contentbox.models.content.BaseContent" + name="parent" + cfc="contentbox.models.content.BaseContent" fieldtype="many-to-one" - fkcolumn ="FK_parentID" - lazy ="true"; + fkcolumn="FK_parentID" + lazy="true"; // O2M -> Sub Content Inverse property - name ="children" + name="children" singularName="child" - fieldtype ="one-to-many" - type ="array" - lazy ="extra" - batchsize ="25" - orderby ="createdDate" - cfc ="contentbox.models.content.BaseContent" - fkcolumn ="FK_parentID" - inverse ="true" - cascade ="all-delete-orphan"; + fieldtype="one-to-many" + type="array" + lazy="extra" + batchsize="25" + orderby="createdDate" + cfc="contentbox.models.content.BaseContent" + fkcolumn="FK_parentID" + inverse="true" + cascade="all-delete-orphan"; // O2M -> Comment Subscribers property - name ="commentSubscriptions" + name="commentSubscriptions" singularName="commentSubscription" - fieldtype ="one-to-many" - type ="array" - lazy ="true" - batchsize ="25" - cfc ="contentbox.models.subscriptions.CommentSubscription" - fkcolumn ="FK_contentID" - inverse ="true" - cascade ="all-delete-orphan"; + fieldtype="one-to-many" + type="array" + lazy="true" + batchsize="25" + cfc="contentbox.models.subscriptions.CommentSubscription" + fkcolumn="FK_contentID" + inverse="true" + cascade="all-delete-orphan"; // M2M -> Categories property - name ="categories" - fieldtype ="many-to-many" - type ="array" - lazy ="true" - orderby ="category" - cascade ="save-update" - cfc ="contentbox.models.content.Category" - fkcolumn ="FK_contentID" - linktable ="cb_contentCategories" + name="categories" + fieldtype="many-to-many" + type="array" + lazy="true" + batchsize="25" + orderby="category" + cascade="save-update" + cfc="contentbox.models.content.Category" + fkcolumn="FK_contentID" + linktable="cb_contentCategories" inversejoincolumn="FK_categoryID"; // M2M -> Related Content - Content related from this content to other content property - name ="relatedContent" - fieldtype ="many-to-many" - type ="array" - lazy ="true" - orderby ="title" - cascade ="save-update" - cfc ="contentbox.models.content.BaseContent" - fkcolumn ="FK_contentID" - linktable ="cb_relatedContent" + name="relatedContent" + fieldtype="many-to-many" + type="array" + lazy="true" + batchsize="25" + orderby="title" + cascade="save-update" + cfc="contentbox.models.content.BaseContent" + fkcolumn="FK_contentID" + linktable="cb_relatedContent" inversejoincolumn="FK_relatedContentID"; // M2M -> Linked Content - Content related to this content from other content property - name ="linkedContent" - fieldtype ="many-to-many" - type ="array" - lazy ="true" - cascade ="save-update" - inverse ="true" - orderby ="title" - cfc ="contentbox.models.content.BaseContent" - fkcolumn ="FK_relatedContentID" - linktable ="cb_relatedContent" + name="linkedContent" + fieldtype="many-to-many" + type="array" + lazy="true" + batchsize="25" + cascade="save-update" + inverse="true" + orderby="title" + cfc="contentbox.models.content.BaseContent" + fkcolumn="FK_relatedContentID" + linktable="cb_relatedContent" inversejoincolumn="FK_contentID"; - // O2O -> Content Stats - property - name ="stats" - notnull ="true" - cfc ="contentbox.models.content.Stats" - fieldtype="one-to-one" - mappedBy ="relatedContent" - cascade ="all-delete-orphan"; - property - name ="contentTemplate" + name="contentTemplate" fieldtype="many-to-one" - cfc ="contentbox.models.content.ContentTemplate" - fkcolumn ="FK_contentTemplateID" - lazy ="true"; + cfc="contentbox.models.content.ContentTemplate" + fkcolumn="FK_contentTemplateID" + lazy="true"; property - name ="childContentTemplate" + name="childContentTemplate" fieldtype="many-to-one" - cfc ="contentbox.models.content.ContentTemplate" - fkcolumn ="FK_childContentTemplateID" - lazy ="true"; + cfc="contentbox.models.content.ContentTemplate" + fkcolumn="FK_childContentTemplateID" + lazy="true"; /** * -------------------------------------------------------------------------- @@ -424,27 +421,9 @@ component */ property - name ="numberOfHits" - formula="select cbStats.hits - from cb_stats cbStats - where cbStats.FK_contentID=contentID" - default="0"; - - property - name ="numberOfChildren" - formula="select count(*) from cb_content content where content.FK_parentID=contentID" - default="0"; - - property - name ="numberOfComments" + name="numberOfComments" formula="select count(*) from cb_comment comment where comment.FK_contentID=contentID" default="0"; - - property - name ="numberOfVersions" - formula="select count(*) from cb_contentVersion versions where versions.FK_contentID=contentID" - default="0"; - /** * -------------------------------------------------------------------------- * MEMENTIFIER + CONSTRAINTS @@ -454,7 +433,7 @@ component this.pk = "contentID"; this.memento = { - defaultIncludes : [ + defaultIncludes: [ "allowComments", "cache", "cacheLastAccessTimeout", @@ -489,20 +468,13 @@ component "siteID", "title" ], - defaultExcludes : [ - "comments", - "commentSubscriptions", - "contentVersions", - "contentTemplate", - "site", - "stats" - ], - neverInclude : [ "passwordProtection" ], - mappers : {}, - defaults : { "stats" : {}, "contentTemplate" : {} }, - profiles : { - response : { - defaultIncludes : [ + defaultExcludes: [ "comments", "commentSubscriptions", "contentVersions", "contentTemplate", "site"], + neverInclude : [ "passwordProtection"], + mappers : {}, + defaults : { "contentTemplate": {} }, + profiles : { + response: { + defaultIncludes: [ "categoriesArray:categories", "contentID", "contentType", @@ -525,10 +497,10 @@ component "renderedExcerpt", "childrenSnapshot:children" ], - defaultExcludes : [] + defaultExcludes: [] }, - export : { - defaultIncludes : [ + export: { + defaultIncludes: [ "allowComments", "cache", "cacheLastAccessTimeout", @@ -562,10 +534,9 @@ component "contentTemplate", "customFields", "linkedContentSnapshot:linkedContent", - "relatedContentSnapshot:relatedContent", - "stats" + "relatedContentSnapshot:relatedContent" ], - defaultExcludes : [ + defaultExcludes: [ "commentSubscriptions.relatedContentSnapshot:relatedContent", "children.parentSnapshot:parent", "linkedContent", @@ -579,82 +550,90 @@ component }; this.constraints = { - "cacheLastAccessTimeout" : { required : false, type : "numeric" }, - "cacheTimeout" : { required : false, type : "numeric" }, - "expireDate" : { required : false, type : "date" }, - "featuredImage" : { required : false, size : "1..255" }, - "HTMLDescription" : { required : false, size : "1..160" }, - "HTMLKeywords" : { required : false, size : "1..160" }, - "markup" : { required : true, size : "1..100" }, - "passwordProtection" : { required : false, size : "1..100" }, - "publishedDate" : { required : false, type : "date" }, - "site" : { required : true }, - "slug" : { - required : true, - size : "1..200", - udfMessage : "The 'slug' is not unique", - udf : function( value, target ){ - return arguments.target + "cacheLastAccessTimeout": { required: false, type: "numeric" }, + "cacheTimeout" : { required: false, type: "numeric" }, + "expireDate" : { required: false, type: "date" }, + "featuredImage" : { required: false, size: "1..255" }, + "HTMLDescription" : { required: false, size: "1..160" }, + "HTMLKeywords" : { required: false, size: "1..160" }, + "markup" : { required: true, size: "1..100" }, + "passwordProtection" : { required: false, size: "1..100" }, + "publishedDate" : { required: false, type: "date" }, + "site" : { required: true }, + "slug" : { + required : true, + size : "1..200", + udfMessage: "The 'slug' is not unique", + udf : function( value, target ) { + return arguments + .target .getContentService() .isSlugUnique( - contentType: arguments.target.getContentType(), - slug : arguments.value, - contentID : arguments.target.isLoaded() ? arguments.target.getContentID() : "", - siteID : arguments.target.hasSite() ? arguments.target.getSite().getSiteID() : "" + contentType = arguments.target.getContentType(), + slug = arguments.value, + contentID = arguments.target.isLoaded() ? arguments.target.getContentID() : "", + siteID = arguments.target.hasSite() + ? arguments + .target + .getSite() + .getSiteID() + : "" ); } }, - "title" : { required : true, size : "1..200" } + "title": { required: true, size: "1..200" } }; /** * Base constructor */ - function init(){ + function init() { super.init(); - variables.isPublished = true; - variables.publishedDate = now(); - variables.allowComments = true; - variables.cache = true; - variables.cacheTimeout = 0; + variables.isPublished = true; + variables.publishedDate = now(); + variables.allowComments = true; + variables.cache = true; + variables.cacheTimeout = 0; variables.cacheLastAccessTimeout = 0; - variables.markup = "HTML"; - variables.contentType = ""; - variables.showInSearch = true; - variables.renderedContent = ""; - variables.children = []; + variables.markup = "HTML"; + variables.contentType = ""; + variables.showInSearch = true; + variables.renderedContent = ""; + variables.children = []; return this; } /** * Prepare the instance for usage */ - function onDIComplete(){ + function onDIComplete() { // Load up content helpers - variables.wirebox - .getInstance( dsl: "coldbox:moduleSettings:contentbox" ) + variables + .wirebox + .getInstance( dsl = "coldbox:moduleSettings:contentbox" ) .contentHelpers - .each( function( thisHelper ){ - includeMixin( arguments.thisHelper ); - } ); + .each( + function( thisHelper ) { + includeMixin( arguments.thisHelper ); + } + ); } - /** * Utility method to get a snapshot of this content object */ - struct function getInfoSnapshot(){ + struct function getInfoSnapshot() { if ( isLoaded() ) { return { - "contentID" : getContentID(), - "title" : getTitle(), - "slug" : getSlug(), - "isPublished" : getIsPublished(), - "publishedDate" : getPublishedDate(), - "createdDate" : getCreatedDate(), - "modifiedDate" : getModifiedDate(), - "expireDate" : getExpireDate(), - "contentType" : getContentType() + "contentID" : getContentID(), + "title" : getTitle(), + "slug" : getSlug(), + "isPublished" : getIsPublished(), + "publishedDate": getPublishedDate(), + "createdDate" : getCreatedDate(), + "modifiedDate" : getModifiedDate(), + "expireDate" : getExpireDate(), + "contentType" : getContentType() }; } return {}; @@ -663,21 +642,21 @@ component /** * Build a parent snapshot */ - struct function getParentSnapshot(){ + struct function getParentSnapshot() { return ( hasParent() ? getParent().getInfoSnapshot() : {} ); } /** * Build a creator snapshot */ - struct function getCreatorSnapshot(){ + struct function getCreatorSnapshot() { return ( hasCreator() ? getCreator().getInfoSnapshot() : {} ); } /** * Build a last editor snapshot */ - struct function getLastEditorSnapshot(){ + struct function getLastEditorSnapshot() { var activeContent = getActiveContent(); return ( activeContent.hasAuthor() ? activeContent.getAuthor().getInfoSnapshot() : {} ); } @@ -685,95 +664,108 @@ component /** * Build a site snapshot */ - struct function getSiteSnapshot(){ + struct function getSiteSnapshot() { return ( hasSite() ? getSite().getInfoSnapshot() : {} ); } /** - * Get the number of hits + * Get the number of hits from the stats service */ - numeric function getNumberOfHits(){ - return ( isNull( variables.numberOfHits ) ? 0 : variables.numberOfHits ); + numeric function getNumberOfHits() { + if ( !isLoaded() ) { + return 0; + } + return variables.statsService.getTotalHitsByContent( getContentID() ); } /** - * Get the number of children + * Get the number of children from the children relationship */ - numeric function getNumberOfChildren(){ - return ( isNull( variables.numberOfChildren ) ? 0 : variables.numberOfChildren ); + numeric function getNumberOfChildren() { + if ( !isLoaded() || !hasChild() ) { + return 0; + } + return arrayLen( variables.children ); } /** * Get the total number of comments this content object has */ - numeric function getNumberOfComments(){ + numeric function getNumberOfComments() { return ( isNull( variables.numberOfComments ) ? 0 : variables.numberOfComments ); } /** * Get the total number of approved comments this content object has */ - numeric function getNumberOfApprovedComments(){ + numeric function getNumberOfApprovedComments() { if ( !isLoaded() ) { return 0; } - return variables.comments - .filter( function( comment ){ - return comment.getIsApproved(); - } ) - .len(); + return variables + .commentService + .newCriteria() + .isEq( "relatedContent.contentID", getContentID() ) + .isEq( "isApproved", javacast( "boolean", true ) ) + .count(); } /** - * Get the total number of versions this content object has + * Get the total number of versions this content object has from the contentVersions relationship */ - numeric function getNumberOfVersions(){ - return ( isNull( variables.numberOfVersions ) ? 0 : variables.numberOfVersions ); + numeric function getNumberOfVersions() { + if ( !isLoaded() || !hasContentVersion() ) { + return 0; + } + return arrayLen( variables.contentVersions ); } /** * Get the total number of active versions this content object has */ - numeric function getNumberOfActiveVersions(){ + numeric function getNumberOfActiveVersions() { return ( isLoaded() ? variables.contentVersionService.getNumberOfVersions( getContentId(), true ) : 0 ); } - /** * Getter overload to return either the assigned template or the global template for the site * * @note The hierarchy for templates is local, parent assigned, and then any globals */ - any function getContentTemplate(){ + any function getContentTemplate() { return !isNull( variables.contentTemplate ) - ? variables.contentTemplate - : ( - !isNull( getParent() ) && !isNull( getParent().getChildContentTemplate() ) - ? getParent().getChildContentTemplate() - : getContentTemplateService() - .newCriteria() - .isEq( "contentType", getContentType() ) - .isEq( "site", getSite() ) - .isEq( "isGlobal", javacast( "boolean", true ) ) - .get() - ); + ? variables.contentTemplate + : ( + !isNull( getParent() ) && !isNull( getParent().getChildContentTemplate() ) + ? getParent().getChildContentTemplate() + : getContentTemplateService() + .newCriteria() + .isEq( "contentType", getContentType() ) + .isEq( "site", getSite() ) + .isEq( "isGlobal", javacast( "boolean", true ) ) + .get() + ); } /** * Returns the URL of the featured image */ - function getFeaturedImageURL(){ + function getFeaturedImageURL() { var featured = getFeaturedImage(); if ( isNull( featured ) || !len( featured ) ) { return ""; } - var mediaRoot = mediaService.getCoreMediaRoot(); + var mediaRoot = mediaService.getCoreMediaRoot(); var expandedMediaRoot = expandPath( mediaRoot ); // We have three scenarios in how the featured image entries are stored. // The first is that the image was stored with a fully expanded path if ( findNoCase( expandedMediaRoot, featured ) ) { return replaceNoCase( - replaceNoCase( featured, expandedMediaRoot, "/__media" ), + replaceNoCase( + featured, + expandedMediaRoot, + "/__media" + ), "\", "/", "All" @@ -783,16 +775,18 @@ component if ( findNoCase( mediaRoot, featured ) ) { // Replace and change any windows delimiters that might be in the path return replaceNoCase( - replaceNoCase( featured, mediaRoot, "/__media" ), + replaceNoCase( + featured, + mediaRoot, + "/__media" + ), "\", "/", "All" ); } // The last is that it is modern cbfs disk paths - return find( ":", featured ) - ? "/__media/" & featured - : featured; + return find( ":", featured ) ? "/__media/" & featured : featured; } /** @@ -810,12 +804,23 @@ component */ BaseContent function addNewContentVersion( required content, - changelog = "", + changelog = "", required author, - boolean isPreview = false - ){ + boolean isPreview = false, + array contentVersions = [] + ) { // lock it for new content creation to avoid version overlaps - lock name="contentbox.addNewContentVersion.#getSlug()#" type="exclusive" timeout="10" throwOnTimeout=true { + lock + name ="contentbox.addNewContentVersion.#getSlug()#" + type ="exclusive" + timeout ="10" + throwOnTimeout="#true#" + { + // Defensive guard for BoxLang populate edge cases where relationship values can become simple values. + if ( !isArray( variables.contentVersions ) ) { + variables.contentVersions = []; + } + // Do we already have an active version? if ( hasActiveContent() ) { // cap checks if not in preview mode @@ -823,18 +828,19 @@ component maxContentVersionChecks(); } // deactive the curent version, we do it after in case the content versions check kick off a transaction - getContentVersions() - .filter( ( version ) => version.getIsActive() ) - .each( ( version ) => version.setIsActive( false ) ); + getContentVersions().filter( ( version ) => version.getIsActive() ).each( ( version + ) => version.setIsActive( false ) ); } // get a new version object with our incoming content + relationships - var oNewVersion = variables.contentVersionService.new( { - content : arguments.content, - changelog : arguments.changelog, - author : arguments.author, - relatedContent : this - } ); + var oNewVersion = variables.contentVersionService.new( + { + content : arguments.content, + changelog : arguments.changelog, + author : arguments.author, + relatedContent: this + } + ); // Get the latest content version, to increase the new version number, collection is ordered by 'version' descending if ( hasContentVersion() ) { @@ -843,7 +849,7 @@ component // Activate the new version oNewVersion.setIsActive( true ); - variables.activeContent = oNewVersion; + variables.activeContent = oNewVersion; variables.renderedContent = ""; // Add it to the content versions array so it can be saved as part of this content object addContentVersion( oNewVersion ); @@ -859,11 +865,14 @@ component /** * Build the array of linked content snapshots */ - array function getLinkedContentSnapshot(){ + array function getLinkedContentSnapshot() { if ( hasLinkedContent() ) { - return arrayMap( variables.linkedContent, function( thisItem ){ - return arguments.thisItem.getInfoSnapshot(); - } ); + return arrayMap( + variables.linkedContent, + function( thisItem ) { + return arguments.thisItem.getInfoSnapshot(); + } + ); } return []; } @@ -871,11 +880,14 @@ component /** * Build the array of children snapshots */ - array function getChildrenSnapshot(){ + array function getChildrenSnapshot() { if ( hasChild() ) { - return arrayMap( variables.children, function( thisItem ){ - return arguments.thisItem.getInfoSnapshot(); - } ); + return arrayMap( + variables.children, + function( thisItem ) { + return arguments.thisItem.getInfoSnapshot(); + } + ); } return []; } @@ -883,11 +895,14 @@ component /** * Build the array of related content snapshots */ - array function getRelatedContentSnapshot(){ + array function getRelatedContentSnapshot() { if ( hasRelatedContent() ) { - return arrayMap( variables.relatedContent, function( thisItem ){ - return arguments.thisItem.getInfoSnapshot(); - } ); + return arrayMap( + variables.relatedContent, + function( thisItem ) { + return arguments.thisItem.getInfoSnapshot(); + } + ); } return []; } @@ -895,11 +910,14 @@ component /** * Returns a list of active related content for this piece of content */ - string function getRelatedContentIDs(){ + string function getRelatedContentIDs() { if ( hasRelatedContent() ) { - return arrayMap( variables.relatedContent, function( thisItem ){ - return arguments.thisItem.getContentID(); - } ).toList(); + return arrayMap( + variables.relatedContent, + function( thisItem ) { + return arguments.thisItem.getContentID(); + } + ).toList(); } return ""; } @@ -909,7 +927,7 @@ component * * @relatedContent The related content to set */ - BaseContent function setRelatedContent( required array relatedContent ){ + BaseContent function setRelatedContent( required array relatedContent ) { if ( hasRelatedContent() ) { variables.relatedContent.clear(); variables.relatedContent.addAll( arguments.relatedContent ); @@ -924,7 +942,7 @@ component * * @relatedContent The list or array of relatedContent ids */ - BaseContent function inflateRelatedContent( required any relatedContent ){ + BaseContent function inflateRelatedContent( required any relatedContent ) { var allContent = []; // convert to array if ( isSimpleValue( arguments.relatedContent ) ) { @@ -932,7 +950,7 @@ component } // iterate over array for ( var x = 1; x <= arrayLen( arguments.relatedContent ); x++ ) { - var id = trim( arguments.relatedContent[ x ] ); + var id = trim( arguments.relatedContent[ x ] ); // get content from id var extantContent = contentService.get( id ); // if found, add to array @@ -948,21 +966,21 @@ component /** * Determines if the content object can have comments or not */ - boolean function commentsAllowed(){ + boolean function commentsAllowed() { return !isContentStore(); } /** * Determines if the content object is a content store type */ - boolean function isContentStore(){ + boolean function isContentStore() { return getContentType() == "contentStore"; } /** * Override the setComments */ - BaseContent function setComments( required array comments ){ + BaseContent function setComments( required array comments ) { if ( hasComment() ) { variables.comments.clear(); variables.comments.addAll( arguments.comments ); @@ -975,7 +993,7 @@ component /** * Override the setter */ - BaseContent function setCustomFields( required array customFields ){ + BaseContent function setCustomFields( required array customFields ) { if ( hasCustomField() ) { variables.customFields.clear(); variables.customFields.addAll( arguments.customFields ); @@ -988,7 +1006,7 @@ component /** * Get custom fields as a structure representation */ - struct function getCustomFieldsAsStruct(){ + struct function getCustomFieldsAsStruct() { var results = {}; // if no fields, just return empty @@ -1010,7 +1028,7 @@ component * @key The custom field key to get * @defaultValue The default value if the key is not found. */ - any function getCustomField( required key, defaultValue ){ + any function getCustomField( required key, defaultValue ) { var fields = getCustomFieldsAsStruct(); if ( structKeyExists( fields, arguments.key ) ) { return fields[ arguments.key ]; @@ -1028,7 +1046,12 @@ component /** * Override the setContentVersions */ - BaseContent function setContentVersions( required array contentVersions ){ + BaseContent function setContentVersions( required array contentVersions ) { + + if ( !isArray( arguments.contentVersions ) ) { + arguments.contentVersions = []; + } + if ( hasContentVersion() ) { variables.contentVersions.clear(); variables.contentVersions.addAll( arguments.contentVersions ); @@ -1041,7 +1064,7 @@ component /** * Only adds it if not found in content object */ - BaseContent function addCategories( required category ){ + BaseContent function addCategories( required category ) { if ( !hasCategories( arguments.category ) ) { arrayAppend( variables.categories, arguments.category ); } @@ -1051,7 +1074,7 @@ component /** * Remove only if it's found in the content object */ - BaseContent function removeCategories( required category ){ + BaseContent function removeCategories( required category ) { if ( hasCategories( arguments.category ) ) { arrayDelete( variables.categories, arguments.category ); } @@ -1061,7 +1084,7 @@ component /* * I remove all category associations */ - BaseContent function removeAllCategories(){ + BaseContent function removeAllCategories() { if ( hasCategories() ) { variables.categories.clear(); } else { @@ -1073,7 +1096,7 @@ component /* * I remove all custom fields */ - BaseContent function removeAllCustomFields(){ + BaseContent function removeAllCustomFields() { if ( hasCustomField() ) { variables.customFields.clear(); } else { @@ -1085,7 +1108,7 @@ component /* * I remove all linked content associations */ - BaseContent function removeAllLinkedContent(){ + BaseContent function removeAllLinkedContent() { if ( hasLinkedContent() ) { for ( var item in variables.linkedContent ) { item.removeRelatedContent( this ); @@ -1097,7 +1120,7 @@ component /** * Override the setChildren */ - BaseContent function setChildren( required array children ){ + BaseContent function setChildren( required array children ) { if ( hasChild() ) { variables.children.clear(); variables.children.addAll( arguments.children ); @@ -1107,40 +1130,10 @@ component return this; } - /** - * Verify and rotate maximum content versions - */ - private function maxContentVersionChecks(){ - if ( !len( variables.settingService.getSetting( "cb_versions_max_history" ) ) ) { - return; - } - - // How many versions do we have? - var versionCounts = contentVersionService - .newCriteria() - .isEq( "relatedContent.contentID", getContentID() ) - .count(); - - // Have we passed the limit? - if ( ( versionCounts + 1 ) GT variables.settingService.getSetting( "cb_versions_max_history" ) ) { - var oldestVersion = contentVersionService - .newCriteria() - .isEq( "relatedContent.contentID", getContentID() ) - .isEq( "isActive", javacast( "boolean", false ) ) - .withProjections( id = "true" ) - .list( - sortOrder = "createdDate DESC", - offset = variables.settingService.getSetting( "cb_versions_max_history" ) - 2 - ); - // delete by primary key IDs found - contentVersionService.deleteByID( arrayToList( oldestVersion ) ); - } - } - /** * Retrieves the latest content string from the latest version un-translated */ - string function getContent(){ + string function getContent() { return getActiveContent( true ); } @@ -1149,7 +1142,7 @@ component * * @asString Default false. When provided as true, a projection list query to retrieve only the string content will be executed */ - any function getActiveContent( asString = false ){ + any function getActiveContent( asString = false ) { // If we don't have any versions, send back a new one if ( variables.keyExists( "activeContent" ) && !isSimpleValue( variables.activeContent ) ) { return arguments.asString ? variables.activeContent.getContent() : variables.activeContent; @@ -1167,12 +1160,21 @@ component .first(); return activeContentStruct[ "content" ]; } else { - var activeVersions = getContentVersions().filter( ( version ) => version.getIsActive() ); - return activeVersions.len() ? activeVersions.first() : variables.contentVersionService.new(); + var activeVersion = variables + .contentVersionService + .newCriteria() + .isEq( "relatedContent.contentID", getContentID() ) + .isEq( "isActive", javacast( "boolean", true ) ) + .order( "version", "desc" ) + .list( max = 1 ); + return arrayLen( activeVersion ) ? activeVersion[ 1 ] : variables.contentVersionService.new(); } } - function hasActiveContentVersion(){ + /** + * Verify if this content object has any content versions or not + */ + boolean function hasActiveContentVersion() { return ( isLoaded() && hasContentVersion() && getActiveContent().getIsActive() ); } @@ -1181,7 +1183,7 @@ component * * @content The content to set as the active version */ - BaseContent function setActiveContent( required content ){ + BaseContent function setActiveContent( required content ) { variables.activeContent = arguments.content; return this; } @@ -1189,14 +1191,14 @@ component /** * Verify if this content object has an active version with content */ - boolean function hasActiveContent(){ + boolean function hasActiveContent() { return isLoaded() && hasActiveContentVersion(); } /** * Shorthand Creator name */ - string function getCreatorName(){ + string function getCreatorName() { if ( hasCreator() ) { return getCreator().getFullName(); } @@ -1206,7 +1208,7 @@ component /** * Shorthand Creator email */ - string function getCreatorEmail(){ + string function getCreatorEmail() { if ( hasCreator() ) { return getCreator().getEmail(); } @@ -1216,21 +1218,21 @@ component /** * Shorthand Author name from latest version */ - string function getAuthorName(){ + string function getAuthorName() { return getActiveContent().getAuthorName(); } /** * Shorthand Author email from latest version */ - string function getAuthorEmail(){ + string function getAuthorEmail() { return getActiveContent().getAuthorEmail(); } /** * Shorthand Author from latest version or null if any yet */ - any function getAuthor(){ + any function getAuthor() { return getActiveContent().getAuthor(); } @@ -1241,7 +1243,7 @@ component * * @return The parent ID or empty value if none attached */ - function getParentID(){ + function getParentID() { return ( hasParent() ? getParent().getContentID() : "" ); } @@ -1250,47 +1252,45 @@ component * * @return The parent name or empty value if none attached */ - function getParentName(){ + function getParentName() { return ( hasParent() ? getParent().getTitle() : "" ); } /** * Bit that denotes if the content has expired or not, in order to be expired the content must have been published as well */ - boolean function isExpired(){ + boolean function isExpired() { return ( - isContentPublished() AND - !isNull( variables.expireDate ) AND - len( variables.expireDate ) AND // In case of some odd empty string cases - dateCompare( variables.expireDate, now() ) lte 0 - ) ? true : false; + isContentPublished() && !isNull( variables.expireDate ) && len( variables.expireDate ) && + dateCompare( variables.expireDate, now() ) LTE 0 + ) + ? true + : false; } /** * Bit that denotes if the content has been published or not */ - boolean function isContentPublished(){ + boolean function isContentPublished() { return ( - getIsPublished() AND - !isNull( variables.publishedDate ) AND - dateCompare( variables.publishedDate, now() ) lte 0 - ) ? true : false; + getIsPublished() && !isNull( variables.publishedDate ) && + dateCompare( variables.publishedDate, now() ) LTE 0 + ) + ? true + : false; } /** * Bit that denotes if the content has been published or not in the future */ - boolean function isPublishedInFuture(){ - return ( - getIsPublished() AND - dateCompare( variables.publishedDate, now() ) eq 1 - ) ? true : false; + boolean function isPublishedInFuture() { + return ( getIsPublished() && dateCompare( variables.publishedDate, now() ) EQ 1 ) ? true : false; } /** * Is entity loaded */ - boolean function isLoaded(){ + boolean function isLoaded() { return ( len( getContentID() ) ? true : false ); } @@ -1315,26 +1315,26 @@ component required boolean publish, required any originalSlugRoot, required any newSlugRoot - ){ + ) { transaction { // Base Content Property cloning - variables.isPublished = arguments.publish; - variables.createdDate = now(); - variables.modifiedDate = variables.createdDate; - variables.HTMLKeywords = arguments.original.getHTMLKeywords(); - variables.HTMLDescription = arguments.original.getHTMLDescription(); - variables.HTMLTitle = arguments.original.getHTMLTitle(); - variables.markup = arguments.original.getMarkup(); - variables.cache = arguments.original.getCache(); - variables.cacheTimeout = arguments.original.getCacheTimeout(); + variables.isPublished = arguments.publish; + variables.createdDate = now(); + variables.modifiedDate = variables.createdDate; + variables.HTMLKeywords = arguments.original.getHTMLKeywords(); + variables.HTMLDescription = arguments.original.getHTMLDescription(); + variables.HTMLTitle = arguments.original.getHTMLTitle(); + variables.markup = arguments.original.getMarkup(); + variables.cache = arguments.original.getCache(); + variables.cacheTimeout = arguments.original.getCacheTimeout(); variables.cacheLastAccessTimeout = arguments.original.getCacheLastAccessTimeout(); - variables.showInSearch = arguments.original.getShowInSearch(); - variables.featuredImage = arguments.original.getFeaturedImage(); - variables.featuredImageURL = arguments.original.getFeaturedImageURL(); - variables.contentTemplate = arguments.original.getContentTemplate(); - variables.childContentTemplate = arguments.original.getChildContentTemplate(); - variables.comments = []; - variables.children = []; + variables.showInSearch = arguments.original.getShowInSearch(); + variables.featuredImage = arguments.original.getFeaturedImage(); + variables.featuredImageURL = arguments.original.getFeaturedImageURL(); + variables.contentTemplate = arguments.original.getContentTemplate(); + variables.childContentTemplate = arguments.original.getChildContentTemplate(); + variables.comments = []; + variables.children = []; // Are we publishing? if ( arguments.publish ) { @@ -1342,9 +1342,12 @@ component } // get latest content versioning - var latestContent = arguments.original.getActiveContent().getContent(); + var latestContent = arguments + .original + .getActiveContent() + .getContent(); // Original slug updates on all content - latestContent = reReplaceNoCase( + latestContent = reReplaceNoCase( latestContent, "page\:\[#arguments.originalSlugRoot#\/", "page:[#arguments.newSlugRoot#/", @@ -1353,65 +1356,78 @@ component // reset versioning, and start with a new one addNewContentVersion( - content : latestContent, - changelog: "Content Cloned!", - author : arguments.author + content = latestContent, + changelog = "Content Cloned!", + author = arguments.author ); // safe clone custom fields - variables.customFields = arguments.original + variables.customFields = arguments + .original .getCustomFields() - .map( function( thisField ){ - return variables.customFieldService - .new( { - key : arguments.thisField.getKey(), - value : arguments.thisField.getValue() - } ) - .setRelatedContent( this ); - } ); + .map( + function( thisField ) { + return variables + .customFieldService + .new( + { + key : arguments.thisField.getKey(), + value: arguments.thisField.getValue() + } + ) + .setRelatedContent( this ); + } + ); // clone related content - arguments.original + arguments + .original .getRelatedContent() - .each( function( thisRelatedContent ){ - addRelatedContent( arguments.thisRelatedContent ); - } ); + .each( + function( thisRelatedContent ) { + addRelatedContent( arguments.thisRelatedContent ); + } + ); // clone categories - arguments.original + arguments + .original .getCategories() - .each( function( thisCategory ){ - addCategories( variables.categoryService.getOrCreate( arguments.thisCategory, getSite() ) ); - } ); + .each( + function( thisCategory ) { + addCategories( variables.categoryService.getOrCreate( arguments.thisCategory, getSite() ) ); + } + ); // now clone children if ( arguments.original.hasChild() ) { // Save the parent first to avoid cascade issues arguments.originalService.save( this ); // Continue down to clone the original children and attach them - arguments.original + arguments + .original .getChildren() - .each( function( thisChild ){ - // Clone the child - var newChild = originalService - .new( { - creator : author, - title : arguments.thisChild.getTitle(), - slug : listLast( arguments.thisChild.getSlug(), "/" ), - site : getSite() - } ) - .setParent( this ); - - // now deep clone until no more children are left behind. - newChild.clone( - author = author, - original = arguments.thisChild, - originalService = originalService, - publish = publish, - originalSlugRoot = arguments.thisChild.getSlug(), - newSlugRoot = newChild.getSlug() - ); - } ); + .each( + function( thisChild ) { + var newChild = originalService.new( + { + creator: author, + title : arguments.thisChild.getTitle(), + slug : listLast( arguments.thisChild.getSlug(), "/" ), + site : getSite() + } + ).setParent( this ); + + newChild.clone( + author = author, + original = arguments.thisChild, + originalService = originalService, + publish = publish, + originalSlugRoot = arguments.thisChild.getSlug(), + newSlugRoot = newChild.getSlug() + ); + } + ); } else { arguments.originalService.save( this ); } @@ -1428,7 +1444,7 @@ component * * @return The published date time as {hour}:{minute}. */ - string function getPublishedDateTime(){ + string function getPublishedDateTime() { if ( isNull( variables.publishedDate ) || !len( variables.publishedDate ) ) { return ""; } @@ -1441,7 +1457,7 @@ component * * @return The expire date time as {hour}:{minute}. */ - string function getExpireDateTime(){ + string function getExpireDateTime() { if ( isNull( variables.expireDate ) || !len( variables.expireDate ) ) { return ""; } @@ -1460,17 +1476,15 @@ component dateFormat = this.DATE_FORMAT, timeFormat = this.TIME_FORMAT, boolean showTime = true - ){ + ) { if ( isNull( variables.publishedDate ) || !len( variables.publishedDate ) ) { return ""; } if ( !arguments.showTime ) { return dateFormat( variables.publishedDate, arguments.dateFormat ); } - return dateFormat( variables.publishedDate, arguments.dateFormat ) & " " & timeFormat( - variables.publishedDate, - arguments.timeFormat - ); + return dateFormat( variables.publishedDate, arguments.dateFormat ) & " " & timeFormat( variables.publishedDate, + arguments.timeFormat ); } /** @@ -1485,30 +1499,28 @@ component dateFormat = this.DATE_FORMAT, timeFormat = this.TIME_FORMAT, boolean showTime = true - ){ + ) { if ( isNull( variables.expireDate ) || !len( variables.expireDate ) ) { return ""; } if ( !arguments.showTime ) { return dateFormat( variables.expireDate, arguments.dateFormat ); } - return dateFormat( variables.expireDate, arguments.dateFormat ) & " " & timeFormat( - variables.expireDate, - arguments.timeFormat - ); + return dateFormat( variables.expireDate, arguments.dateFormat ) & " " & timeFormat( variables.expireDate, + arguments.timeFormat ); } /** * isPassword Protected */ - boolean function isPasswordProtected(){ + boolean function isPasswordProtected() { return len( getPasswordProtection() ); } /** * add published timestamp to property */ - any function addPublishedTime( required hour, required minute ){ + any function addPublishedTime( required hour, required minute ) { if ( !isDate( getPublishedDate() ) ) { return this; } @@ -1522,7 +1534,7 @@ component * * @timeString The joined time string (e.g., 12:00) */ - any function addJoinedPublishedTime( required string timeString ){ + any function addJoinedPublishedTime( required string timeString ) { var splitTime = listToArray( arguments.timeString, ":" ); if ( arrayLen( splitTime ) == 2 ) { return addPublishedTime( splitTime[ 1 ], splitTime[ 2 ] ); @@ -1534,7 +1546,7 @@ component /** * add expired timestamp to property */ - any function addExpiredTime( required hour, required minute ){ + any function addExpiredTime( required hour, required minute ) { if ( !isDate( getExpireDate() ) ) { return this; } @@ -1556,7 +1568,7 @@ component * * @timeString The joined time string (e.g., 12:00) */ - any function addJoinedExpiredTime( required string timeString ){ + any function addJoinedExpiredTime( required string timeString ) { var splitTime = listToArray( arguments.timeString, ":" ); if ( arrayLen( splitTime ) == 2 ) { return addExpiredTime( splitTime[ 1 ], splitTime[ 2 ] ); @@ -1568,7 +1580,7 @@ component /** * Build content cache keys according to sent content object */ - string function buildContentCacheKey(){ + string function buildContentCacheKey() { var inputHash = hash( cgi.HTTP_HOST & cgi.query_string ); return "cb-content-#getContentType()#-#getContentID()#-#i18n.getfwLocale()#-#inputHash#"; } @@ -1576,20 +1588,20 @@ component /** * This builds a partial cache key so we can clean from the cache many permutations of the content object */ - string function buildContentCacheCleanupKey(){ + string function buildContentCacheCleanupKey() { return "cb-content-#getContentType()#-#getContentID()#"; } /** * Verify we can do content caching on this content object using global and local rules */ - boolean function canCacheContent(){ + boolean function canCacheContent() { var settings = variables.settingService.getAllSettings(); // check global caching first if ( - ( getContentType() eq "page" AND settings.cb_content_caching ) OR - ( getContentType() eq "entry" AND settings.cb_entry_caching ) + ( getContentType() EQ "page" && settings.cb_content_caching ) || + ( getContentType() EQ "entry" && settings.cb_entry_caching ) ) { // check override in local content bit return ( getCache() ? true : false ); @@ -1600,14 +1612,14 @@ component /** * Shortcut to get the rendered content */ - any function getRenderedContent(){ + any function getRenderedContent() { return this.renderContent(); } /** * Shortcut to get the rendered excerpt */ - any function getRenderedExcerpt(){ + any function getRenderedExcerpt() { if ( !isNull( variables.excerpt ) ) { return this.renderExcerpt(); } @@ -1617,25 +1629,25 @@ component /** * Render content out using translations, caching, etc. */ - any function renderContent(){ + any function renderContent() { var settings = variables.settingService.getAllSettings(); // caching enabled? if ( canCacheContent() ) { // Build Cache Key - var cacheKey = buildContentCacheKey(); + var cacheKey = buildContentCacheKey(); // Get appropriate cache provider - var cache = cacheBox.getCache( settings.cb_content_cacheName ); + var cache = cacheBox.getCache( settings.cb_content_cacheName ); // Try to get content? var cachedContent = cache.get( cacheKey ); // Verify it exists, if it does, return it - if ( !isNull( cachedContent ) AND len( cachedContent ) ) { + if ( !isNull( cachedContent ) && len( cachedContent ) ) { return cachedContent; } } // Check if we need to translate - if ( NOT len( variables.renderedContent ) ) { + if ( !len( variables.renderedContent ) ) { // save content variables.renderedContent = renderContentSilent(); } @@ -1644,11 +1656,15 @@ component if ( canCacheContent() ) { // Store content in cache, of local timeouts are 0 then use global timeouts. cache.set( - cacheKey, - variables.renderedContent, - ( getCacheTimeout() eq 0 ? settings.cb_content_cachingTimeout : getCacheTimeout() ), - ( getCacheLastAccessTimeout() eq 0 ? settings.cb_content_cachingTimeoutIdle : getCacheLastAccessTimeout() ) - ); + cacheKey, + variables.renderedContent, + ( getCacheTimeout() EQ 0 ? settings.cb_content_cachingTimeout : getCacheTimeout() ), + ( + getCacheLastAccessTimeout() EQ 0 + ? settings.cb_content_cachingTimeoutIdle + : getCacheLastAccessTimeout() + ) + ); } // renturn translated content @@ -1660,11 +1676,14 @@ component * * @content The content markup to translate, by default it uses the active content version's content */ - any function renderContentSilent( any content = getContent() ) profile{ + any function renderContentSilent( any content = getContent() ) profile { // render content out, prepare builder var builder = createObject( "java", "java.lang.StringBuilder" ).init( arguments.content ); // announce renderings with data, so content renderers can process them - interceptorService.announce( "cb_onContentRendering", { builder : builder, content : this } ); + interceptorService.announce( + "cb_onContentRendering", + { builder: builder, content: this } + ); // return processed content return builder.toString(); } @@ -1672,16 +1691,19 @@ component /** * Inflate custom fields from the incoming count and memento structure */ - any function inflateCustomFields( required numeric fieldCount, required struct memento ){ + any function inflateCustomFields( + required numeric fieldCount, + required struct memento + ) { // remove original custom fields getCustomFields().clear(); // inflate custom fields start at 0 as it is incoming javascript counting of arrays - for ( var x = 0; x lt arguments.fieldCount; x++ ) { + for ( var x = 0; x LT arguments.fieldCount; x++ ) { // get custom field from incoming data var args = { - key : arguments.memento[ "CustomFieldKeys_#x#" ], - value : arguments.memento[ "CustomFieldValues_#x#" ] + key : arguments.memento[ "CustomFieldKeys_#x#" ], + value: arguments.memento[ "CustomFieldValues_#x#" ] }; // only add if key has value if ( len( trim( args.key ) ) ) { @@ -1697,13 +1719,16 @@ component /** * Get an array of category slugs for this content object */ - array function getCategoriesArray(){ - if ( NOT hasCategories() ) { + array function getCategoriesArray() { + if ( !hasCategories() ) { return []; } - return arrayMap( variables.categories, function( item ){ - return arguments.item.getCategory(); - } ); + return arrayMap( + variables.categories, + function( item ) { + return arguments.item.getCategory(); + } + ); } /** @@ -1711,28 +1736,28 @@ component * * @return The category list or `Uncategorized` if it doesn't have any */ - string function getCategoriesList(){ + string function getCategoriesList() { return getCategoriesArray().toList(); } /** * Shortcut to get the site name */ - function getSiteName(){ + function getSiteName() { return getSite().getName(); } /** * Shortcut to get the site slug */ - function getSiteSlug(){ + function getSiteSlug() { return getSite().getSlug(); } /** * Shortcut to get the site id */ - function getSiteID(){ + function getSiteID() { if ( hasSite() ) { return getSite().getsiteID(); } @@ -1744,7 +1769,7 @@ component * * @site The site id or site object to verify */ - boolean function isSameSite( required site ){ + boolean function isSameSite( required site ) { // If no site attached, break. if ( !hasSite() ) { return false; @@ -1764,12 +1789,12 @@ component * * @parent The parent object or null */ - BaseContent function setParent( parent ){ + BaseContent function setParent( parent ) { // Nulllify? if ( isNull( arguments.parent ) ) { variables.parent = javacast( "null", "" ); // remove the hierarchical information from our slug as we are promoting to the root - variables.slug = listLast( variables.slug, "/" ); + variables.slug = listLast( variables.slug, "/" ); return this; } else { // Welcome home papa! @@ -1789,7 +1814,7 @@ component /** * Apply any assigned content templates to this instance */ - BaseContent function applyContentTemplate(){ + BaseContent function applyContentTemplate() { var template = getContentTemplate(); if ( !isNull( template ) ) { var definition = template.getDefintion(); @@ -1799,36 +1824,43 @@ component invoke( this, "populate", - { "memento" : { "#key#" : definition[ key ].value } } + { "memento": { "#key#": definition[ key ].value } } ); } else if ( isArray( currentVal ) ) { switch ( key ) { case "customFields": { var existingFields = getCustomFieldsAsStruct().keyArray(); - definition[ key ].each( function( item ){ - if ( !existingFields.contains( item.name ) ) { - var thisField = customFieldService.new( - properties = { "key" : item.name, "value" : item.defaultValue ?: "" } - ); - thisField.setRelatedContent( this ); - addCustomField( thisField ); - } - } ); + definition[ key ].each( + function( item ) { + if ( !existingFields.contains( item.name ) ) { + var thisField = customFieldService.new( + properties = { + "key" : item.name, + "value": item.defaultValue ?: "" + } + ); + thisField.setRelatedContent( this ); + addCustomField( thisField ); + } + } + ); break; } case "categories": { if ( hasCategories() ) { - var existingCategories = getCategories().map( function( cat ){ - return cat.getCategoryID(); - } ); + var existingCategories = getCategories().map( + function( cat ) { + return cat.getCategoryID(); + } + ); definition[ key ].value.append( existingCategories, true ); } invoke( this, "populate", { - "memento" : { - "#key#" : listToArray( + "memento": { + "#key#": listToArray( listRemoveDuplicates( arrayToList( definition[ key ].value ) ) ) } @@ -1839,15 +1871,49 @@ component invoke( this, "populate", - { "memento" : { "#key#" : definition[ key ].value } } + { "memento": { "#key#": definition[ key ].value } } ); } } } else if ( !len( currentVal ) ) { - invoke( this, "set" & key, [ definition[ key ].value ] ); + invoke( + this, + "set" & key, + [ definition[ key ].value] + ); } } } } -} + /** + * Verify and rotate maximum content versions + */ + private function maxContentVersionChecks() { + if ( !len( variables.settingService.getSetting( "cb_versions_max_history" ) ) ) { + return; + } + + // How many versions do we have? + var versionCounts = contentVersionService + .newCriteria() + .isEq( "relatedContent.contentID", getContentID() ) + .count(); + + // Have we passed the limit? + if ( ( versionCounts + 1 ) GT variables.settingService.getSetting( "cb_versions_max_history" ) ) { + var oldestVersion = contentVersionService + .newCriteria() + .isEq( "relatedContent.contentID", getContentID() ) + .isEq( "isActive", javacast( "boolean", false ) ) + .withProjections( id = "true" ) + .list( + sortOrder = "createdDate DESC", + offset = variables.settingService.getSetting( "cb_versions_max_history" ) - 2 + ); + // delete by primary key IDs found + contentVersionService.deleteByID( arrayToList( oldestVersion ) ); + } + } + +} \ No newline at end of file diff --git a/modules/contentbox/models/content/Category.cfc b/modules/contentbox/models/content/Category.cfc index 51d449366b..2b3c9f03ad 100755 --- a/modules/contentbox/models/content/Category.cfc +++ b/modules/contentbox/models/content/Category.cfc @@ -13,120 +13,91 @@ component cachename ="cbCategory" cacheuse ="read-write" { - - /* ********************************************************************* - ** DI - ********************************************************************* */ + /********************************************************************** + * ** DI + **********************************************************************/ property - name ="categoryService" - inject ="provider:categoryService@contentbox" + name="categoryService" + inject="provider:categoryService@contentbox" persistent="false"; property - name ="pageService" - inject ="provider:pageService@contentbox" + name="pageService" + inject="provider:pageService@contentbox" persistent="false"; property - name ="entryService" - inject ="provider:entryService@contentbox" + name="entryService" + inject="provider:entryService@contentbox" persistent="false"; property - name ="contentStoreService" - inject ="provider:contentStoreService@contentbox" + name="contentStoreService" + inject="provider:contentStoreService@contentbox" persistent="false"; property - name ="settingService" - inject ="provider:settingService@contentbox" + name="settingService" + inject="provider:settingService@contentbox" persistent="false"; - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="categoryID" - column ="categoryID" + name="categoryID" + column="categoryID" fieldtype="id" generator="uuid" - length ="36" - ormtype ="string" - update ="false"; + length="36" + ormtype="string" + update="false"; property - name ="category" - column ="category" + name="category" + column="category" notnull="true" - length ="200" - index ="idx_categoryName"; + length="200" + index="idx_categoryName"; property - name ="slug" - column ="slug" + name="slug" + column="slug" notnull="true" - length ="200" - index ="idx_categorySlug"; + length="200" + index="idx_categorySlug"; property - name ="isPublic" - column ="isPublic" + name="isPublic" + column="isPublic" ormtype="boolean" notnull="false" default="true" - index ="idx_isPublic"; + index="idx_isPublic"; - /* ********************************************************************* - ** RELATIONSHIPS - ********************************************************************* */ + /********************************************************************** + * ** RELATIONSHIPS + **********************************************************************/ // M20 -> site loaded as a proxy and fetched immediately property - name ="site" - notnull ="true" - cfc ="contentbox.models.system.Site" + name="site" + notnull="true" + cfc="contentbox.models.system.Site" fieldtype="many-to-one" - fkcolumn ="FK_siteID" - lazy ="true"; - - /* ********************************************************************* - ** CALCULATED FIELDS - ********************************************************************* */ - - property - name ="numberOfContentStore" - formula="select count(*) - from cb_contentCategories as contentCategories, cb_contentStore as contentStore, cb_content as content - where contentCategories.FK_categoryID=categoryID - and contentCategories.FK_contentID = contentStore.contentID - and contentStore.contentID = content.contentID"; - - property - name ="numberOfEntries" - formula="select count(*) - from cb_contentCategories as contentCategories, cb_entry as entry, cb_content as content - where contentCategories.FK_categoryID=categoryID - and contentCategories.FK_contentID = entry.contentID - and entry.contentID = content.contentID"; - - property - name ="numberOfPages" - formula="select count(*) - from cb_contentCategories as contentCategories, cb_page as page, cb_content as content - where contentCategories.FK_categoryID=categoryID - and contentCategories.FK_contentID = page.contentID - and page.contentID = content.contentID"; - - /* ********************************************************************* - ** PK + CONSTRAINTS + MEMENTO - ********************************************************************* */ + fkcolumn="FK_siteID" + batchsize="25" + lazy="true"; + /********************************************************************** + * ** PK + CONSTRAINTS + MEMENTO + **********************************************************************/ this.pk = "categoryID"; this.memento = { - defaultIncludes : [ + defaultIncludes: [ "category", "isPublic", "numberOfContentStore", @@ -135,42 +106,51 @@ component "slug", "siteSnapshot:site" ], - defaultExcludes : [ "site" ] + defaultExcludes: [ "site"] }; this.constraints = { - "category" : { required : true, size : "1..200" }, - "isPublic" : { required : true, type : "boolean" }, - "slug" : { - required : true, - size : "1..200", - udfMessage : "The 'slug' is not unique", - udf : function( value, target ){ - return arguments.target + "category": { required: true, size: "1..200" }, + "isPublic": { required: true, type: "boolean" }, + "slug" : { + required : true, + size : "1..200", + udfMessage: "The 'slug' is not unique", + udf : function( value, target ) { + return arguments + .target .getCategoryService() .isSlugUnique( - slug : arguments.value, - categoryID: arguments.target.isLoaded() ? arguments.target.getCategoryID() : "", - siteID : arguments.target.hasSite() ? arguments.target.getSite().getSiteID() : "" + slug = arguments.value, + categoryID = arguments.target.isLoaded() ? arguments.target.getCategoryID() : "", + siteID = arguments.target.hasSite() + ? arguments + .target + .getSite() + .getSiteID() + : "" ); } } }; - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ /** * Constructor */ - function init(){ - variables.category = ""; - variables.slug = ""; - variables.numberOfPublishedPages = ""; - variables.numberOfPublishedEntries = ""; + function init() { + variables.category = ""; + variables.slug = ""; + variables.numberOfEntries = ""; + variables.numberOfPages = ""; + variables.numberOfContentStore = ""; + variables.numberOfPublishedPages = ""; + variables.numberOfPublishedEntries = ""; variables.numberOfPublishedContentStore = ""; - variables.isPublic = true; + variables.isPublic = true; super.init(); @@ -180,10 +160,10 @@ component /** * Helper to get the count of published pages for this category. */ - numeric function getNumberOfPublishedPages(){ + numeric function getNumberOfPublishedPages() { // Caching per load basis if ( !len( variables.numberOfPublishedPages ) ) { - variables.numberOfPublishedPages = getNumberOfPublishedContent( variables.pageService ); + variables.numberOfPublishedPages = getNumberOfPublishedContent( variables.pageService, "pages" ); } return variables.numberOfPublishedPages; } @@ -191,10 +171,11 @@ component /** * Helper to get the count of published content store for this category. */ - numeric function getNumberOfPublishedContentStore(){ + numeric function getNumberOfPublishedContentStore() { // Caching per load basis if ( !len( variables.numberOfPublishedContentStore ) ) { - variables.numberOfPublishedContentStore = getNumberOfPublishedContent( variables.contentStoreService ); + variables.numberOfPublishedContentStore = getNumberOfPublishedContent( variables.contentStoreService, + "contentstore" ); } return variables.numberOfPublishedContentStore; } @@ -202,10 +183,10 @@ component /** * Helper to get the count of published entries for this category. */ - numeric function getNumberOfPublishedEntries(){ + numeric function getNumberOfPublishedEntries() { // Caching per load basis if ( !len( variables.numberOfPublishedEntries ) ) { - variables.numberOfPublishedEntries = getNumberOfPublishedContent( variables.entryService ); + variables.numberOfPublishedEntries = getNumberOfPublishedContent( variables.entryService, "entries" ); } return variables.numberOfPublishedEntries; } @@ -213,45 +194,102 @@ component /** * Build a site snapshot */ - struct function getSiteSnapshot(){ + struct function getSiteSnapshot() { return ( hasSite() ? getSite().getInfoSnapshot() : {} ); } /** * Shortcut to get the site id */ - function getSiteID(){ + function getSiteID() { if ( hasSite() ) { return getSite().getsiteID(); } return ""; } + /** + * Get the total number of entries (regardless of published state) for this category. + */ + numeric function getNumberOfEntries() { + if ( !len( variables.numberOfEntries ) ) { + variables.numberOfEntries = getNumberOfTotalContent( variables.entryService, "entries" ); + } + return variables.numberOfEntries; + } + + /** + * Get the total number of pages (regardless of published state) for this category. + */ + numeric function getNumberOfPages() { + if ( !len( variables.numberOfPages ) ) { + variables.numberOfPages = getNumberOfTotalContent( variables.pageService, "pages" ); + } + return variables.numberOfPages; + } + + /** + * Get the total number of content store items (regardless of published state) for this category. + */ + numeric function getNumberOfContentStore() { + if ( !len( variables.numberOfContentStore ) ) { + variables.numberOfContentStore = getNumberOfTotalContent( variables.contentStoreService, "contentstore" ); + } + return variables.numberOfContentStore; + } + /********************************** PRIVATE **********************************/ /** - * Get the number of published content by category and service type + * Get the count of all (total) content for this category by service type. + * Results are cached in CacheBox per category slug and content type. + * + * @service The target content service to use. + * @contentType A discriminator string baked into the cache key (e.g. "entries", "pages", "contentstore"). + */ + private numeric function getNumberOfTotalContent( required service, required string contentType ) { + return variables + .cacheBox + .getCache( variables.settingService.getSetting( "cb_content_cacheName" ) ) + .getOrSet( + "cb-content-category-total-counts-#getSlug()#-#arguments.contentType#", + function() { + return service + .newCriteria() + .createAlias( "categories", "categories" ) + .isEq( "categories.categoryID", getCategoryID() ?: "" ) + .count( "contentID" ); + } + ); + } + + /** + * Get the number of published content by category and service type. + * Results are cached in CacheBox per category slug and content type. * - * @service The target service to use. + * @service The target content service to use. + * @contentType A discriminator string baked into the cache key (e.g. "entries", "pages", "contentstore"). */ - private numeric function getNumberOfPublishedContent( required service ){ - return variables.cacheBox + private numeric function getNumberOfPublishedContent( required service, required string contentType ) { + return variables + .cacheBox .getCache( variables.settingService.getSetting( "cb_content_cacheName" ) ) - .getOrSet( "cb-content-category-counts-#getSlug()#", function(){ - return service - .newCriteria() - .createAlias( "categories", "categories" ) - .isEq( "categories.categoryID", getCategoryID() ) - .isTrue( "isPublished" ) - .isLE( "publishedDate", now() ) - .isEq( "passwordProtection", "" ) - .$or( - service.getRestrictions().isNull( "expireDate" ), - service.getRestrictions().isGT( "expireDate", now() ) - ) - .cache( true ) - .count( "contentID" ); - } ); + .getOrSet( + "cb-content-category-counts-#getSlug()#-#arguments.contentType#", + function() { + return service + .newCriteria() + .createAlias( "categories", "categories" ) + .isEq( "categories.categoryID", getCategoryID() ) + .isTrue( "isPublished" ) + .isLE( "publishedDate", now() ) + .isEq( "passwordProtection", "" ) + .$or( service.getRestrictions().isNull( "expireDate" ), + service.getRestrictions().isGT( "expireDate", now() ) ) + .cache( true ) + .count( "contentID" ); + } + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/CategoryService.cfc b/modules/contentbox/models/content/CategoryService.cfc index 0dc10fcdee..3ab49282be 100755 --- a/modules/contentbox/models/content/CategoryService.cfc +++ b/modules/contentbox/models/content/CategoryService.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -6,16 +6,17 @@ * Category service for contentbox */ component extends="cborm.models.VirtualEntityService" singleton { - // Dependencies property name="htmlHelper" inject="HTMLHelper@coldbox"; + property name="contentService" inject="contentService@contentbox"; + property name="dateUtil" inject="DateUtil@contentbox"; /** * Constructor */ - CategoryService function init(){ + CategoryService function init() { // init it super.init( entityName = "cbCategory", useQueryCaching = true ); @@ -35,35 +36,46 @@ component extends="cborm.models.VirtualEntityService" singleton { * @return struct of { count, categories } */ struct function search( - search = "", - siteID = "", + search = "", + siteID = "", boolean isPublic, max = 0, offset = 0, sortOrder = "category asc" - ){ - var results = { "count" : 0, "categories" : [] }; - var c = newCriteria() + ) { + var results = { "count": 0, "categories": [] }; + var c = newCriteria() + .when( + len( arguments.search ), + function( c ) { + c.like( "category", "%#search#%" ); + } + ) + .when( + len( arguments.siteID ), + function( c ) { + c.isEq( "site.siteID", siteID ); + } + ) // Search Criteria - .when( len( arguments.search ), function( c ){ - c.like( "category", "%#search#%" ); - } ) + // Site Filter - .when( len( arguments.siteID ), function( c ){ - c.isEq( "site.siteID", siteID ); - } ) + // IsPublic Filter - .when( !isNull( arguments.isPublic ), function( c ){ - c.isEq( "isPublic", javacast( "Boolean", isPublic ) ); - } ); + .when( + !isNull( arguments.isPublic ), + function( c ) { + c.isEq( "isPublic", javacast( "Boolean", isPublic ) ); + } + ); // run criteria query and projections count - results.count = c.count( "categoryID" ); + results.count = c.count( "categoryID" ); results.categories = c.list( - offset : arguments.offset, - max : arguments.max, - sortOrder: arguments.sortOrder - ); + offset = arguments.offset, + max = arguments.max, + sortOrder = arguments.sortOrder + ); return results; } @@ -78,7 +90,7 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @return The target site category */ - Category function getOrCreate( required category, required site ){ + Category function getOrCreate( required category, required site ) { // Verify the incoming category exists in the target site or not var oTargetCategory = newCriteria() .isEq( "slug", arguments.category.getSlug() ) @@ -89,11 +101,13 @@ component extends="cborm.models.VirtualEntityService" singleton { // Return or Create if ( isNull( oTargetCategory ) ) { oTargetCategory = save( - new ( { - category : arguments.category.getCategory(), - slug : arguments.category.getSlug(), - site : arguments.site - } ) + new( + { + category: arguments.category.getCategory(), + slug : arguments.category.getSlug(), + site : arguments.site + } + ) ); } @@ -110,7 +124,7 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @return The target site category object */ - Category function getOrCreateBySlug( required string category, required site ){ + Category function getOrCreateBySlug( required string category, required site ) { // Verify the incoming category exists in the target site or not if ( arguments.site.isLoaded() ) { var oTargetCategory = newCriteria() @@ -122,11 +136,13 @@ component extends="cborm.models.VirtualEntityService" singleton { // Return or Create if ( isNull( oTargetCategory ) ) { var oTargetCategory = save( - new ( { - category : arguments.category, - slug : arguments.category, - site : arguments.site - } ) + new( + { + category: arguments.category, + slug : arguments.category, + site : arguments.site + } + ) ); } @@ -138,12 +154,13 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @siteID The site to filter on */ - numeric function getTotalCategoryCount( string siteID = "" ){ - return newCriteria() - .when( len( arguments.siteID ), function( c ){ - c.isEq( "site.siteID", siteID ); - } ) - .count(); + numeric function getTotalCategoryCount( string siteID = "" ) { + return newCriteria().when( + len( arguments.siteID ), + function( c ) { + c.isEq( "site.siteID", siteID ); + } + ).count(); } /** @@ -155,7 +172,7 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @throws UniqueCategoryException */ - function save( required category ){ + function save( required category ) { return super.save( arguments.category ); } @@ -172,16 +189,25 @@ component extends="cborm.models.VirtualEntityService" singleton { required any slug, any categoryID = "", string siteID = "" - ){ + ) { return newCriteria() - .isEq( "slug", arguments.slug ) - .when( len( arguments.siteID ), function( c ){ - c.isEq( "site.siteID", siteID ); - } ) - .when( len( arguments.categoryID ), function( c ){ - c.ne( "categoryID", categoryID ); - } ) - .count() > 0 ? false : true; + .isEq( "slug", arguments.slug ) + .when( + len( arguments.siteID ), + function( c ) { + c.isEq( "site.siteID", siteID ); + } + ) + .when( + len( arguments.categoryID ), + function( c ) { + c.ne( "categoryID", categoryID ); + } + ) + .count() > + 0 + ? false + : true; } /** @@ -195,28 +221,37 @@ component extends="cborm.models.VirtualEntityService" singleton { required categories, required site, boolean isPublic = true - ){ + ) { // convert to array if ( isSimpleValue( arguments.categories ) ) { arguments.categories = listToArray( arguments.categories ); } - var allCats = arguments.categories + var allCats = arguments + .categories + .filter( + function( thisCategory ) { + return newCriteria() + .isEq( "category", arguments.thisCategory ) + .isEq( "site.siteID", site.getsiteID() ) + .count() == + 0; + } + ) // Only create categories that do not exist already - .filter( function( thisCategory ){ - return newCriteria() - .isEq( "category", arguments.thisCategory ) - .isEq( "site.siteID", site.getsiteID() ) - .count() == 0; - } ) - .map( function( thisCategory ){ - return new ( { - "category" : thisCategory, - "slug" : variables.htmlHelper.slugify( thisCategory ), - "site" : site, - "isPublic" : isPublic - } ); - } ); + + .map( + function( thisCategory ) { + return new( + { + "category": thisCategory, + "slug" : variables.htmlHelper.slugify( thisCategory ), + "site" : site, + "isPublic": isPublic + } + ); + } + ); // Save all cats if ( arrayLen( allCats ) ) { @@ -233,7 +268,7 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @return array of categories */ - array function inflateCategories( struct memento ){ + array function inflateCategories( struct memento ) { var categories = []; // iterate all memento keys for ( var key in arguments.memento ) { @@ -255,7 +290,7 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @category The category object to remove from the system */ - boolean function delete( required category ){ + boolean function delete( required category ) { transaction { // Remove content relationships var aRelatedContent = removeAllRelatedContent( arguments.category ); @@ -277,7 +312,7 @@ component extends="cborm.models.VirtualEntityService" singleton { * Remove all content associations from a category and returns all the content objects it was removed from * @category.hint The category object */ - array function removeAllRelatedContent( required category ){ + array function removeAllRelatedContent( required category ) { var aRelatedContent = contentService .newCriteria() .createAlias( "categories", "c" ) @@ -297,10 +332,12 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @site The site to export from */ - array function getAllForExport( required site ){ - return findAllWhere( { site : arguments.site } ).map( function( thisItem ){ - return thisItem.getMemento( profile: "export" ); - } ); + array function getAllForExport( required site ) { + return findAllWhere( { site: arguments.site } ).map( + function( thisItem ) { + return thisItem.getMemento( profile = "export" ); + } + ); } /** @@ -309,16 +346,22 @@ component extends="cborm.models.VirtualEntityService" singleton { * @siteId The site to filter the names from * @isPublic If passed, show by this filter, else all categories */ - array function getAllNames( string siteID = "", boolean isPublic ){ + array function getAllNames( string siteID = "", boolean isPublic ) { return newCriteria() - .withProjections( property: "category" ) - .when( len( arguments.siteID ), function( c ){ - c.isEq( "site.siteID", siteID ); - } ) - .when( !isNull( arguments.isPublic ), function( c ){ - c.isEq( "isPublic", javacast( "Boolean", isPublic ) ); - } ) - .list( sortOrder: "category" ); + .withProjections( property = "category" ) + .when( + len( arguments.siteID ), + function( c ) { + c.isEq( "site.siteID", siteID ); + } + ) + .when( + !isNull( arguments.isPublic ), + function( c ) { + c.isEq( "isPublic", javacast( "Boolean", isPublic ) ); + } + ) + .list( sortOrder = "category" ); } /** @@ -327,16 +370,22 @@ component extends="cborm.models.VirtualEntityService" singleton { * @siteId The site to filter the names from * @isPublic If passed, show by this filter, else all categories */ - array function getAllSlugs( string siteID = "", boolean isPublic ){ + array function getAllSlugs( string siteID = "", boolean isPublic ) { return newCriteria() - .withProjections( property: "slug" ) - .when( len( arguments.siteID ), function( c ){ - c.isEq( "site.siteID", siteID ); - } ) - .when( !isNull( arguments.isPublic ), function( c ){ - c.isEq( "isPublic", javacast( "Boolean", isPublic ) ); - } ) - .list( sortOrder: "slug" ); + .withProjections( property = "slug" ) + .when( + len( arguments.siteID ), + function( c ) { + c.isEq( "site.siteID", siteID ); + } + ) + .when( + !isNull( arguments.isPublic ), + function( c ) { + c.isEq( "isPublic", javacast( "Boolean", isPublic ) ); + } + ) + .list( sortOrder = "slug" ); } /** @@ -349,14 +398,17 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @throws InvalidImportFormat */ - string function importFromFile( required importFile, boolean override = false ){ - var data = fileRead( arguments.importFile ); + string function importFromFile( required importFile, boolean override = false ) { + var data = fileRead( arguments.importFile ); var importLog = createObject( "java", "java.lang.StringBuilder" ).init( - "Starting import with override = #arguments.override#...
" - ); + "Starting import with override = #arguments.override#...
" + ); if ( !isJSON( data ) ) { - throw( message = "Cannot import file as the contents is not JSON", type = "InvalidImportFormat" ); + throw( + message = "Cannot import file as the contents is not JSON", + type = "InvalidImportFormat" + ); } // deserialize packet: Should be array of { settingID, name, value } @@ -382,29 +434,29 @@ component extends="cborm.models.VirtualEntityService" singleton { required importData, boolean override = false, importLog - ){ + ) { var allCategories = []; - var siteService = getWireBox().getInstance( "siteService@contentbox" ); + var siteService = getWireBox().getInstance( "siteService@contentbox" ); // if struct, inflate into an array if ( isStruct( arguments.importData ) ) { - arguments.importData = [ arguments.importData ]; + arguments.importData = [ arguments.importData]; } transaction { // iterate and import for ( var thisCategory in arguments.importData ) { // Get new or persisted - var oCategory = this.findBySlug( slug: thisCategory.slug ); - oCategory = ( isNull( oCategory ) ? new () : oCategory ); + var oCategory = this.findBySlug( slug = thisCategory.slug ); + oCategory = ( isNull( oCategory ) ? new() : oCategory ); // populate content from data getBeanPopulator().populateFromStruct( - target : oCategory, - memento : thisCategory, - exclude : "categoryID", - composeRelationships: false - ); + target = oCategory, + memento = thisCategory, + exclude = "categoryID", + composeRelationships = false + ); // Link the site oCategory.setSite( siteService.getBySlugOrFail( thisCategory.site.slug ) ); @@ -413,7 +465,7 @@ component extends="cborm.models.VirtualEntityService" singleton { if ( !oCategory.isLoaded() ) { arguments.importLog.append( "New category imported: #thisCategory.slug#
" ); arrayAppend( allCategories, oCategory ); - } else if ( oCategory.isLoaded() and arguments.override ) { + } else if ( oCategory.isLoaded() && arguments.override ) { arguments.importLog.append( "Persisted category overriden: #thisCategory.slug#
" ); arrayAppend( allCategories, oCategory ); } else { @@ -428,8 +480,8 @@ component extends="cborm.models.VirtualEntityService" singleton { arguments.importLog.append( "Saved all imported and overriden categories!" ); } else { arguments.importLog.append( - "No categories imported as none where found or able to be overriden from the import file." - ); + "No categories imported as none where found or able to be overriden from the import file." + ); } } // end of transaction @@ -437,4 +489,4 @@ component extends="cborm.models.VirtualEntityService" singleton { return arguments.importLog.toString(); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/ContentService.cfc b/modules/contentbox/models/content/ContentService.cfc index dfbcd7c3f4..f2b793322d 100755 --- a/modules/contentbox/models/content/ContentService.cfc +++ b/modules/contentbox/models/content/ContentService.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -6,25 +6,43 @@ * A generic content service for content objects */ component extends="cborm.models.VirtualEntityService" singleton { - // DI property name="settingService" inject="id:settingService@contentbox"; + property name="cacheBox" inject="cachebox"; + property name="log" inject="logbox:logger:{this}"; + property name="customFieldService" inject="customFieldService@contentbox"; + property name="categoryService" inject="categoryService@contentbox"; + property name="commentService" inject="commentService@contentbox"; + property name="contentVersionService" inject="contentVersionService@contentbox"; + property name="authorService" inject="authorService@contentbox"; + property name="contentStoreService" inject="contentStoreService@contentbox"; + property name="pageService" inject="pageService@contentbox"; + property name="entryService" inject="entryService@contentbox"; + property name="systemUtil" inject="SystemUtil@contentbox"; + property name="statsService" inject="statsService@contentbox"; + property name="dateUtil" inject="DateUtil@contentbox"; - property name="commentSubscriptionService" inject="CommentSubscriptionService@contentbox"; + + property + name="commentSubscriptionService" + inject="CommentSubscriptionService@contentbox"; + property name="subscriberService" inject="subscriberService@contentbox"; + property name="relocationService" inject="RelocationService@contentbox"; + property name="asyncManager" inject="coldbox:asyncManager"; /** @@ -32,7 +50,7 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @entityName The content entity name to bind this service to. */ - ContentService function init( entityName = "cbContent" ){ + ContentService function init( entityName = "cbContent" ) { // init it super.init( entityName = arguments.entityName, useQueryCaching = true ); @@ -45,14 +63,18 @@ component extends="cborm.models.VirtualEntityService" singleton { * @siteID The site to filter on * @categoryId The category Id to filter on */ - numeric function getTotalContentCount( siteID = "", categoryId = "" ){ - var c = newCriteria() - .when( len( arguments.siteID ), function( c ){ - c.isEq( "site.siteID", siteID ); - } ) - .when( len( arguments.categoryId ), function( c ){ - c.joinTo( "categories", "cats" ).isEq( "cats.categoryID", categoryId ); - } ); + numeric function getTotalContentCount( siteID = "", categoryId = "" ) { + var c = newCriteria().when( + len( arguments.siteID ), + function( c ) { + c.isEq( "site.siteID", siteID ); + } + ).when( + len( arguments.categoryId ), + function( c ) { + c.joinTo( "categories", "cats" ).isEq( "cats.categoryID", categoryId ); + } + ); return c.count(); } @@ -61,8 +83,9 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @async Run it asynchronously or not, defaults to false */ - ContentService function clearAllCaches( boolean async = false ){ - variables.cacheBox + ContentService function clearAllCaches( boolean async = false ) { + variables + .cacheBox .getCache( variables.settingService.getSetting( "cb_content_cacheName" ) ) .clearByKeySnippet( keySnippet = "cb-content", async = arguments.async ); return this; @@ -73,8 +96,9 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @async Run it asynchronously or not, defaults to false */ - ContentService function clearAllCategoryCountCaches( boolean async = false ){ - variables.cacheBox + ContentService function clearAllCategoryCountCaches( boolean async = false ) { + variables + .cacheBox .getCache( variables.settingService.getSetting( "cb_content_cacheName" ) ) .clearByKeySnippet( keySnippet = "cb-content-category-counts", async = arguments.async ); return this; @@ -85,8 +109,9 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @async Run it asynchronously or not, defaults to false */ - ContentService function clearAllSitemapCaches( boolean async = false ){ - variables.cacheBox + ContentService function clearAllSitemapCaches( boolean async = false ) { + variables + .cacheBox .getCache( variables.settingService.getSetting( "cb_content_cacheName" ) ) .clearByKeySnippet( keySnippet = "cb-content-sitemap", async = arguments.async ); return this; @@ -97,8 +122,9 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @async Run it asynchronously or not, defaults to false */ - ContentService function clearAllPageWrapperCaches( boolean async = false ){ - variables.cacheBox + ContentService function clearAllPageWrapperCaches( boolean async = false ) { + variables + .cacheBox .getCache( variables.settingService.getSetting( "cb_content_cacheName" ) ) .clearByKeySnippet( keySnippet = "cb-content-wrapper", async = arguments.async ); return this; @@ -110,8 +136,9 @@ component extends="cborm.models.VirtualEntityService" singleton { * @slug The slug partial to clean on * @async Run it asynchronously or not, defaults to false */ - ContentService function clearPageWrapperCaches( required any slug, boolean async = false ){ - variables.cacheBox + ContentService function clearPageWrapperCaches( required any slug, boolean async = false ) { + variables + .cacheBox .getCache( variables.settingService.getSetting( "cb_content_cacheName" ) ) .clearByKeySnippet( keySnippet = "cb-content-wrapper-[^-]*-#arguments.slug#", @@ -127,8 +154,9 @@ component extends="cborm.models.VirtualEntityService" singleton { * @slug The slug to clear * @async Run it asynchronously or not, defaults to false */ - ContentService function clearPageWrapper( required any slug, boolean async = false ){ - variables.cacheBox + ContentService function clearPageWrapper( required any slug, boolean async = false ) { + variables + .cacheBox .getCache( variables.settingService.getSetting( "cb_content_cacheName" ) ) .clear( "cb-content-wrapper-#cgi.HTTP_HOST#-#arguments.slug#/" ); return this; @@ -163,20 +191,24 @@ component extends="cborm.models.VirtualEntityService" singleton { string contentTypes = "", any excludeIDs = "", boolean showInSearch, - string siteID = "", + string siteID = "", string propertyList - ){ - var results = { "count" : 0, "content" : [] }; - var c = newCriteria(); + ) { + var results = { "count": 0, "content": [] }; + var c = newCriteria(); // only published contentwithClause if ( isBoolean( arguments.isPublished ) ) { // Published bit - c.isEq( "isPublished", javacast( "Boolean", arguments.isPublished ) ); + c.isEq( + "isPublished", + javacast( "Boolean", arguments.isPublished ) + ); // Published eq true evaluate other params if ( arguments.isPublished ) { - c.isLt( "publishedDate", now() ) + c + .isLt( "publishedDate", now() ) .$or( c.restrictions.isNull( "expireDate" ), c.restrictions.isGT( "expireDate", now() ) ) .isEq( "passwordProtection", "" ); } @@ -184,7 +216,10 @@ component extends="cborm.models.VirtualEntityService" singleton { // only search shownInSearch bits if ( structKeyExists( arguments, "showInSearch" ) ) { - c.isEq( "showInSearch", javacast( "Boolean", arguments.showInSearch ) ); + c.isEq( + "showInSearch", + javacast( "Boolean", arguments.showInSearch ) + ); } // Search Criteria @@ -192,11 +227,10 @@ component extends="cborm.models.VirtualEntityService" singleton { // Do we search title and active content or just title? if ( arguments.searchActiveContent ) { c.createAlias( - associationName: "contentVersions", - alias : "ac", - withClause : getRestrictions().isTrue( "ac.isActive" ) - ) - .$or( + associationName = "contentVersions", + alias = "ac", + withClause = getRestrictions().isTrue( "ac.isActive" ) + ).$or( c.restrictions.like( "title", "%#arguments.searchTerm#%" ), c.restrictions.like( "ac.content", "%#arguments.searchTerm#%" ) ); @@ -233,11 +267,11 @@ component extends="cborm.models.VirtualEntityService" singleton { c.resultTransformer( c.DISTINCT_ROOT_ENTITY ); } results.content = c.list( - offset = arguments.offset, - max = arguments.max, - sortOrder = arguments.sortOrder, - asQuery = arguments.asQuery - ); + offset = arguments.offset, + max = arguments.max, + sortOrder = arguments.sortOrder, + asQuery = arguments.asQuery + ); return results; } @@ -250,13 +284,16 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @return The id of the content object or empty string if not found */ - function getIdBySlug( required any slug, string siteID = "" ){ + function getIdBySlug( required any slug, string siteID = "" ) { var results = newCriteria() .isEq( "slug", arguments.slug ) - .when( len( arguments.siteID ), function( c ){ - c.isEq( "site.siteID", siteID ); - } ) - .withProjections( property: "contentID" ) + .when( + len( arguments.siteID ), + function( c ) { + c.isEq( "site.siteID", siteID ); + } + ) + .withProjections( property = "contentID" ) .get(); // verify results @@ -270,18 +307,20 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @throws EntityNotFound */ - function getByIdOrSlugOrFail( required id ){ - var c = newCriteria(); - var oEntity = c - .$or( - // note: id is a shortcut in Hibernate for the Primary Key + function getByIdOrSlugOrFail( required id ) { + var c = newCriteria(); + var oEntity = c.$or( c.restrictions.isEq( "id", arguments.id ), c.restrictions.isEq( "slug", arguments.id ) - ) + )// note: id is a shortcut in Hibernate for the Primary Key + .get(); if ( isNull( oEntity ) ) { - throw( message = "No entity found for ID/Slug #arguments.id.toString()#", type = "EntityNotFound" ); + throw( + message = "No entity found for ID/Slug #arguments.id.toString()#", + type = "EntityNotFound" + ); } return oEntity; @@ -301,21 +340,28 @@ component extends="cborm.models.VirtualEntityService" singleton { required any slug, required boolean showUnpublished = false, string siteID = "" - ){ + ) { var oContent = newCriteria() .isEq( "slug", arguments.slug ) - .when( len( arguments.siteID ), function( c ){ - c.isEq( "site.siteID", siteID ); - } ) - .when( !showUnpublished, function( c ){ - c.isTrue( "isPublished" ) - .isLT( "publishedDate", now() ) - .$or( c.restrictions.isNull( "expireDate" ), c.restrictions.isGT( "expireDate", now() ) ); - } ) + .when( + len( arguments.siteID ), + function( c ) { + c.isEq( "site.siteID", siteID ); + } + ) + .when( + !showUnpublished, + function( c ) { + c + .isTrue( "isPublished" ) + .isLT( "publishedDate", now() ) + .$or( c.restrictions.isNull( "expireDate" ), c.restrictions.isGT( "expireDate", now() ) ); + } + ) .get(); // return accordingly - return isNull( oContent ) ? new () : oContent; + return isNull( oContent ) ? new() : oContent; } /** @@ -333,19 +379,31 @@ component extends="cborm.models.VirtualEntityService" singleton { any contentID = "", string siteID = "", string contentType = "" - ){ + ) { return newCriteria() - .isEq( "slug", arguments.slug ) - .when( len( arguments.siteID ), function( c ){ - c.isEq( "site.siteID", siteID ); - } ) - .when( len( arguments.contentId ), function( c ){ - c.ne( "contentID", contentId ); - } ) - .when( len( arguments.contentType ), function( c ){ - c.isEq( "contentType", contentType ); - } ) - .count() > 0 ? false : true; + .isEq( "slug", arguments.slug ) + .when( + len( arguments.siteID ), + function( c ) { + c.isEq( "site.siteID", siteID ); + } + ) + .when( + len( arguments.contentId ), + function( c ) { + c.ne( "contentID", contentId ); + } + ) + .when( + len( arguments.contentType ), + function( c ) { + c.isEq( "contentType", contentType ); + } + ) + .count() > + 0 + ? false + : true; } /** @@ -353,17 +411,23 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @content the Content object to delete */ - ContentService function delete( required any content ){ + ContentService function delete( required any content ) { transaction { // Check for dis-associations if ( arguments.content.hasParent() ) { - arguments.content.getParent().removeChild( arguments.content ); + arguments + .content + .getParent() + .removeChild( arguments.content ); } if ( arguments.content.hasCategories() ) { arguments.content.removeAllCategories(); } if ( arguments.content.hasRelatedContent() ) { - arguments.content.getRelatedContent().clear(); + arguments + .content + .getRelatedContent() + .clear(); } if ( arguments.content.hasLinkedContent() ) { arguments.content.removeAllLinkedContent(); @@ -407,22 +471,22 @@ component extends="cborm.models.VirtualEntityService" singleton { * @return struct as { count, content } */ function findPublishedContent( - numeric max = 0, - numeric offset = 0, - any searchTerm = "", - any category = "", - boolean asQuery = false, - string sortOrder = "publishedDate DESC", + numeric max = 0, + numeric offset = 0, + any searchTerm = "", + any category = "", + boolean asQuery = false, + string sortOrder = "publishedDate DESC", any parent, string slugPrefix = "", string siteID = "", string properties, - string authorID = "", + string authorID = "", any criteria, string slugSearch = "" - ){ - var results = { "count" : 0, "content" : [] }; - var c = ( isNull( arguments.criteria ) ? newCriteria() : arguments.criteria ); + ) { + var results = { "count": 0, "content": [] }; + var c = ( isNull( arguments.criteria ) ? newCriteria() : arguments.criteria ); // Do we evaluate parent roots or not? var nullParentFields = [ @@ -432,79 +496,112 @@ component extends="cborm.models.VirtualEntityService" singleton { arguments.slugPrefix, arguments.slugSearch ]; - var hasSearchContext = nullParentFields.reduce( function( results, thisItem ){ - if ( len( arguments.thisItem ) ) { - return true; - } - return results; - }, false ); + var hasSearchContext = nullParentFields.reduce( + function( results, thisItem ) { + if ( len( arguments.thisItem ) ) { + return true; + } + return results; + }, + false + ); // only published pages - c.isTrue( "isPublished" ) + c + .isTrue( "isPublished" ) .isLT( "publishedDate", now() ) .$or( c.restrictions.isNull( "expireDate" ), c.restrictions.isGT( "expireDate", now() ) ) - // only non-password pages .isEq( "passwordProtection", "" ) - // Category Filter - .when( len( arguments.category ), function( c ){ - // create association with categories by slug. - arguments.c.joinTo( "categories", "cats" ).isIn( "cats.slug", listToArray( category ) ); - } ) - // Search Criteria - .when( len( arguments.searchTerm ), function( c ){ - // like disjunctions - arguments.c - .joinTo( - associationName: "contentVersions", - alias : "ac", - withClause : getRestrictions().isTrue( "ac.isActive" ) - ) - .$or( - arguments.c.restrictions.like( "title", "%#searchTerm#%" ), - arguments.c.restrictions.like( "slug", "%#searchTerm#%" ), - arguments.c.restrictions.like( "ac.content", "%#searchTerm#%" ) - ); - } ) - // Slug Search Criteria - .when( len( arguments.slugSearch ), function( c ){ - arguments.c.ilike( "slug", "%#slugSearch#%" ); - } ) - // Site Filter - .when( len( arguments.siteID ), function( c ){ - arguments.c.isEq( "site.siteID", siteID ); - } ) - // Creator Filter - .when( len( arguments.authorID ), function( c ){ - arguments.c.isEq( "creator.authorID", authorID ); - } ) - // Slug Prefix hierarchy search - .when( len( arguments.slugPrefix ), function( c ){ - arguments.c.ilike( "slug", "#slugPrefix#/%" ); - } ) - // Parent Included Filter - .when( !isNull( arguments.parent ) && len( arguments.parent ), function( c ){ - arguments.c.isEq( "parent.contentID", parent ); - } ) - // Parent Root when parent = '' - .when( !isNull( arguments.parent ) && !len( arguments.parent ) && !hasSearchContext, function( c ){ - // change sort by parent - arguments.c.isNull( "parent" ); - sortOrder = "order asc"; - } ) - ; + .when( + len( arguments.category ), + function( c ) { + arguments + .c + .joinTo( "categories", "cats" ) + .isIn( "cats.slug", listToArray( category ) ); + } + ) + .when( + len( arguments.searchTerm ), + function( c ) { + arguments + .c + .joinTo( + associationName = "contentVersions", + alias = "ac", + withClause = getRestrictions().isTrue( "ac.isActive" ) + ) + .$or( + arguments + .c + .restrictions + .like( "title", "%#searchTerm#%" ), + arguments + .c + .restrictions + .like( "slug", "%#searchTerm#%" ), + arguments + .c + .restrictions + .like( "ac.content", "%#searchTerm#%" ) + ); + } + ) + .when( + len( arguments.slugSearch ), + function( c ) { + arguments.c.ilike( "slug", "%#slugSearch#%" ); + } + ) + .when( + len( arguments.siteID ), + function( c ) { + arguments.c.isEq( "site.siteID", siteID ); + } + ) + .when( + len( arguments.authorID ), + function( c ) { + arguments.c.isEq( "creator.authorID", authorID ); + } + ) + .when( + len( arguments.slugPrefix ), + function( c ) { + arguments.c.ilike( "slug", "#slugPrefix#/%" ); + } + ) + .when( + !isNull( arguments.parent ) && len( arguments.parent ), + function( c ) { + arguments.c.isEq( "parent.contentID", parent ); + } + ) + .when( + !isNull( arguments.parent ) && !len( arguments.parent ) && !hasSearchContext, + function( c ) { + arguments.c.isNull( "parent" ); + sortOrder = "order asc"; + } + ); // run criteria query and projections count - results.count = c.count( "contentID" ); - results.content = c - // Do we want array of simple projections? - .when( !isNull( arguments.properties ), function( c ){ - arguments.c.withProjections( property: properties ).asStruct(); - } ) + results.count = c.count( "contentID" ); + results.content = c.when( + !isNull( arguments.properties ), + function( c ) { + arguments + .c + .withProjections( property = properties ) + .asStruct(); + } + )// Do we want array of simple projections? + .list( - offset : arguments.offset, - max : arguments.max, - sortOrder: arguments.sortOrder, - asQuery : arguments.asQuery + offset = arguments.offset, + max = arguments.max, + sortOrder = arguments.sortOrder, + asQuery = arguments.asQuery ); return results; @@ -516,17 +613,17 @@ component extends="cborm.models.VirtualEntityService" singleton { * @contentID The list or array of ID's to bulk update * @status The status either 'publish' or 'draft' */ - any function bulkPublishStatus( required any contentID, required any status ){ + any function bulkPublishStatus( required any contentID, required any status ) { var publish = false; // publish flag - if ( arguments.status eq "publish" ) { + if ( arguments.status EQ "publish" ) { publish = true; } // Get all by id var contentObjects = getAll( id = arguments.contentID ); - for ( var x = 1; x lte arrayLen( contentObjects ); x++ ) { + for ( var x = 1; x LTE arrayLen( contentObjects ); x++ ) { contentObjects[ x ].setpublishedDate( now() ); contentObjects[ x ].setisPublished( publish ); } @@ -550,15 +647,16 @@ component extends="cborm.models.VirtualEntityService" singleton { numeric max = 0, numeric offset = 0, string siteID = "" - ){ + ) { var c = newCriteria().createAlias( - associationName: "contentVersions", - alias : "ac", - withClause : getRestrictions().isTrue( "ac.isActive" ) - ); + associationName = "contentVersions", + alias = "ac", + withClause = getRestrictions().isTrue( "ac.isActive" ) + ); // only future published pages - c.isTrue( "isPublished" ) + c + .isTrue( "isPublished" ) .isLT( "publishedDate", now() ) .isLT( "expireDate", now() ); @@ -573,11 +671,11 @@ component extends="cborm.models.VirtualEntityService" singleton { } return c.list( - max = arguments.max, - offset = arguments.offset, - sortOrder = "expireDate desc", - asQuery = false - ); + max = arguments.max, + offset = arguments.offset, + sortOrder = "expireDate desc", + asQuery = false + ); } /** @@ -593,12 +691,12 @@ component extends="cborm.models.VirtualEntityService" singleton { numeric max = 0, numeric offset = 0, string siteID = "" - ){ + ) { var c = newCriteria().createAlias( - associationName: "contentVersions", - alias : "ac", - withClause : getRestrictions().isTrue( "ac.isActive" ) - ); + associationName = "contentVersions", + alias = "ac", + withClause = getRestrictions().isTrue( "ac.isActive" ) + ); // Only non-expired future publishing pages c.isTrue( "isPublished" ).isGT( "publishedDate", now() ); @@ -614,11 +712,11 @@ component extends="cborm.models.VirtualEntityService" singleton { } return c.list( - max = arguments.max, - offset = arguments.offset, - sortOrder = "publishedDate desc", - asQuery = false - ); + max = arguments.max, + offset = arguments.offset, + sortOrder = "publishedDate desc", + asQuery = false + ); } /** @@ -634,27 +732,39 @@ component extends="cborm.models.VirtualEntityService" singleton { boolean isPublished, numeric max = 25, string siteID = "" - ){ + ) { // Get only active content joins return newCriteria() .createAlias( - associationName: "contentVersions", - alias : "ac", - withClause : getRestrictions().isTrue( "ac.isActive" ) + associationName = "contentVersions", + alias = "ac", + withClause = getRestrictions().isTrue( "ac.isActive" ) + ) + .when( + !isNull( arguments.isPublished ), + function( c ) { + c.isEq( "isPublished", javacast( "boolean", isPublished ) ); + } + ) + .when( + !isNull( arguments.siteID ), + function( c ) { + c.isEq( "site.siteID", siteID ); + } + ) + .when( + !isNull( arguments.author ), + function( c ) { + c.isEq( "ac.author", author ); + } ) // isPublished filter - .when( !isNull( arguments.isPublished ), function( c ){ - c.isEq( "isPublished", javacast( "boolean", isPublished ) ); - } ) + // Site Filter - .when( !isNull( arguments.siteID ), function( c ){ - c.isEq( "site.siteID", siteID ); - } ) + // author filter - .when( !isNull( arguments.author ), function( c ){ - c.isEq( "ac.author", author ); - } ) - .list( max: arguments.max, sortOrder: "ac.createdDate desc" ); + + .list( max = arguments.max, sortOrder = "ac.createdDate desc" ); } /** @@ -662,14 +772,27 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @max The maximum to retrieve, defaults to 5 entries * @siteID The site to filter on + * + * @return An array of structures with contentId, label and hits keys */ - array function getTopVisitedContent( numeric max = 5, string siteID = "" ){ - return newCriteria() - .when( len( arguments.siteID ), function( c ){ - c.isEq( "site.siteID", siteID ); - } ) - .joinTo( "stats", "stats" ) - .list( max = arguments.max, sortOrder = "stats.hits desc" ); + array function getTopVisitedContent( numeric max = 5, string siteID = "" ) { + return variables.statsService + .newCriteria() + .when( + len( arguments.siteID ), + ( c ) => { + c + .joinTo( "relatedContent", "relatedContent" ) + .isEq( "relatedContent.site.siteID", siteID ); + } + ) + .list( max = arguments.max, sortOrder = "hits desc" ) + .map( ( stat ) => { return { + "contentId" : stat.getRelatedContent().getContentID(), + "label" : stat.getRelatedContent().getTitle(), + "hits" : stat.getHits(), + "content" : stat.getRelatedContent() + } } ) } /** @@ -678,23 +801,22 @@ component extends="cborm.models.VirtualEntityService" singleton { * @max The maximum to retrieve, defaults to 5 entries * @siteID The site to filter on */ - array function getTopCommentedContent( numeric max = 5, string siteID = "" ){ + array function getTopCommentedContent( numeric max = 5, string siteID = "" ) { return executeQuery( - query: " + query = " SELECT new map( content as content, count( comments.commentID ) AS commentCount ) FROM cbContent content JOIN content.comments comments WHERE content.site.siteID = :siteID GROUP BY content ORDER BY count( comments.commentID ) DESC ", - params : { siteID : arguments.siteID }, - max : arguments.max, - ignoreCase: true - ) - // We just need the content objects, not the comments count - .map( function( item ){ - return item[ "content" ]; - } ); + params = { siteID: arguments.siteID }, + max = arguments.max, + ignoreCase = true + )// We just need the content objects, not the comments count + .map( function( item ) { + return item[ "content" ]; + } ); } /** @@ -702,13 +824,15 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @inData The data to use for exporting, usually concrete implementtions can override this. */ - array function getAllForExport( any inData ){ + array function getAllForExport( any inData ) { if ( isNull( arguments.inData ) ) { arguments.inData = newCriteria().isNull( "parent" ).list(); } - return arguments.inData.map( function( thisItem ){ - return arguments.thisItem.getMemento( profile: "export" ); - } ); + return arguments.inData.map( + function( thisItem ) { + return arguments.thisItem.getMemento( profile = "export" ); + } + ); } /** @@ -721,14 +845,17 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @throws InvalidImportFormat */ - string function importFromFile( required importFile, boolean override = false ){ - var data = fileRead( arguments.importFile ); + string function importFromFile( required importFile, boolean override = false ) { + var data = fileRead( arguments.importFile ); var importLog = createObject( "java", "java.lang.StringBuilder" ).init( - "Starting import with override = #arguments.override#...
" - ); + "Starting import with override = #arguments.override#...
" + ); if ( !isJSON( data ) ) { - throw( message: "Cannot import file as the contents is not JSON", type: "InvalidImportFormat" ); + throw( + message = "Cannot import file as the contents is not JSON", + type = "InvalidImportFormat" + ); } // deserialize packet: Should be array of { settingID, name, value } @@ -754,9 +881,9 @@ component extends="cborm.models.VirtualEntityService" singleton { boolean override = false, required importLog, site - ){ + ) { // Setup logging function - var logThis = function( message ){ + var logThis = function( message ) { variables.logger.info( arguments.message ); importLog.append( arguments.message & "
" ); }; @@ -765,7 +892,7 @@ component extends="cborm.models.VirtualEntityService" singleton { // if struct, inflate into an array if ( isStruct( arguments.importData ) ) { - arguments.importData = [ arguments.importData ]; + arguments.importData = [ arguments.importData]; } transaction { @@ -773,7 +900,9 @@ component extends="cborm.models.VirtualEntityService" singleton { for ( var thisContent in arguments.importData ) { // Determine Site if not passed from import data if ( isNull( arguments.site ) ) { - logThis( "+ Site not passed, inflating from import data (#thisContent.site.slug#)" ); + logThis( + "+ Site not passed, inflating from import data (#thisContent.site.slug#)" + ); arguments.site = siteService.getBySlugOrFail( thisContent.site.slug ); } @@ -783,17 +912,19 @@ component extends="cborm.models.VirtualEntityService" singleton { // Import it importFromStruct( - contentData: thisContent, - importLog : arguments.importLog, - site : arguments.site, - override : arguments.override + contentData = thisContent, + importLog = arguments.importLog, + site = arguments.site, + override = arguments.override ); } // end import loop // Save content if ( !arrayLen( arguments.importData ) ) { - logThis( "No content imported as none where found or able to be overriden from the import file." ); + logThis( + "No content imported as none where found or able to be overriden from the import file." + ); } } // end transaction @@ -819,10 +950,10 @@ component extends="cborm.models.VirtualEntityService" singleton { any parent, struct newContent = {}, required site, - boolean override = false - ){ + boolean override = false + ) { // Setup logging function - var logThis = function( message ){ + var logThis = function( message ) { variables.logger.info( arguments.message ); importLog.append( arguments.message & "
" ); }; @@ -830,7 +961,7 @@ component extends="cborm.models.VirtualEntityService" singleton { var thisContent = arguments.contentData; // Get content by slug, if not found then it returns a new entity so we can persist it. - var oContent = findWhere( { "slug" : thisContent.slug, "site" : arguments.site } ); + var oContent = findWhere( { "slug": thisContent.slug, "site": arguments.site } ); if ( isNull( oContent ) ) { logThis( "! Content (#thisContent.contentType#:#thisContent.slug#) not found in site, proceeding to import as new content." @@ -875,12 +1006,12 @@ component extends="cborm.models.VirtualEntityService" singleton { "stats" ]; getBeanPopulator().populateFromStruct( - target = oContent, - memento = thisContent, - exclude = arrayToList( excludedFields ), - composeRelationships = false, - nullEmptyInclude = "publishedDate,expireDate" - ); + target = oContent, + memento = thisContent, + exclude = arrayToList( excludedFields ), + composeRelationships = false, + nullEmptyInclude = "publishedDate,expireDate" + ); // determine author else ignore import var oAuthor = variables.authorService.findByEmail( thisContent.creator.email ); @@ -893,20 +1024,24 @@ component extends="cborm.models.VirtualEntityService" singleton { // AUTHOR CREATOR oContent.setCreator( oAuthor ); - logThis( "+ Content author linked for: (#thisContent.contentType#:#thisContent.slug#)" ); + logThis( + "+ Content author linked for: (#thisContent.contentType#:#thisContent.slug#)" + ); // PARENT - if ( !isNull( arguments.parent ) and isObject( arguments.parent ) ) { + if ( !isNull( arguments.parent ) && isObject( arguments.parent ) ) { oContent.setParent( arguments.parent ); arguments.parent.addChild( oContent ); logThis( "+ Content parent (#arguments.parent.getSlug()#) passed and linked for: (#thisContent.contentType#:#thisContent.slug#)" ); } else if ( structCount( thisContent.parent ) ) { - var oParent = findWhere( { - "slug" : thisContent.parent.slug, - "site" : arguments.site - } ); + var oParent = findWhere( + { + "slug": thisContent.parent.slug, + "site": arguments.site + } + ); // assign if persisted if ( !isNull( oParent ) ) { oContent.setParent( oParent ); @@ -923,16 +1058,17 @@ component extends="cborm.models.VirtualEntityService" singleton { // CATEGORIES if ( arrayLen( thisContent.categories ) ) { oContent.setCategories( - thisContent.categories.map( function( thisCategory ){ - var oSiteCategory = site.getCategory( arguments.thisCategory ); - return ( - !isNull( oSiteCategory ) ? oSiteCategory : variables.categoryService.getOrCreateBySlug( - arguments.thisCategory, - site + thisContent.categories.map( + function( thisCategory ) { + var oSiteCategory = site.getCategory( arguments.thisCategory ); + return ( + !isNull( oSiteCategory ) + ? oSiteCategory + : variables.categoryService.getOrCreateBySlug( arguments.thisCategory, site ) + ); + } ) - ); - } ) - ); + ); logThis( "+ Categories (#thisContent.categories.toString()#) imported for : (#thisContent.contentType#:#thisContent.slug#)" ); @@ -953,26 +1089,42 @@ component extends="cborm.models.VirtualEntityService" singleton { // explicitly convert value to string... // ACF doesn't handle string values well when they look like numbers :) oContent.addCustomField( - customFieldService.new( { - key : thisCF.key, - value : toString( thisCF.value ), - relatedContent : oContent - } ) + customFieldService.new( + { + key : thisCF.key, + value : toString( thisCF.value ), + relatedContent: oContent + } + ) + ); + logThis( + "+ Custom field (#thisCF.key#) imported for : (#thisContent.contentType#:#thisContent.slug#)" ); - logThis( "+ Custom field (#thisCF.key#) imported for : (#thisContent.contentType#:#thisContent.slug#)" ); } } // STATS if ( structCount( thisContent.stats ) && thisContent.stats.hits > 0 ) { - if ( oContent.hasStats() ) { - oContent.getStats().setHits( thisContent.stats.hits ); - logThis( "+ Content stats found and updated for : (#thisContent.contentType#:#thisContent.slug#)" ); + var oStat = variables + .statsService + .newCriteria() + .isEq( "relatedContent.contentID", oContent.getContentID() ) + .get(); + if ( !isNull( oStat ) ) { + oStat.setHits( thisContent.stats.hits ); + variables.statsService.save( oStat ); + logThis( + "+ Content stats found and updated for : (#thisContent.contentType#:#thisContent.slug#)" + ); } else { - logThis( "+ Content stats imported for : (#thisContent.contentType#:#thisContent.slug#)" ); - variables.statsService.save( - variables.statsService.new( { hits : thisContent.stats.hits, relatedContent : oContent } ) + logThis( + "+ Content stats imported for : (#thisContent.contentType#:#thisContent.slug#)" ); + variables.statsService.save( + variables.statsService.new( + { hits: thisContent.stats.hits, relatedContent: oContent } + ) + ); } } @@ -1018,13 +1170,14 @@ component extends="cborm.models.VirtualEntityService" singleton { logThis( "+ Related content (#thisRelatedContent.slug#) already imported, linking to : (#thisContent.contentType#:#thisContent.slug#)" ); - } - // otherwise, we need to get it - else { - var oRelatedContent = getServiceByType( thisRelatedContent.contentType ).findWhere( { - "slug" : thisRelatedContent.slug, - "site" : arguments.site - } ); + } else { + // otherwise, we need to get it + var oRelatedContent = getServiceByType( thisRelatedContent.contentType ).findWhere( + { + "slug": thisRelatedContent.slug, + "site": arguments.site + } + ); if ( !isNull( oRelatedContent ) ) { arrayAppend( allRelatedContent, oRelatedContent ); logThis( @@ -1046,18 +1199,20 @@ component extends="cborm.models.VirtualEntityService" singleton { "+ Content comments (#arrayLen( thisContent.comments )#) found, about to start import for : (#thisContent.contentType#:#thisContent.slug#)" ); oContent.setComments( - thisContent.comments.map( function( thisComment ){ - return getBeanPopulator() - .populateFromStruct( - target = variables.commentService.new(), - memento = thisComment, - exclude = "commentID", - composeRelationships = false + thisContent.comments.map( + function( thisComment ) { + return getBeanPopulator().populateFromStruct( + target = variables.commentService.new(), + memento = thisComment, + exclude = "commentID", + composeRelationships = false + ).setRelatedContent( oContent ); + } ) - .setRelatedContent( oContent ); - } ) + ); + logThis( + "+ Content comments imported to: (#thisContent.contentType#:#thisContent.slug#)" ); - logThis( "+ Content comments imported to: (#thisContent.contentType#:#thisContent.slug#)" ); } // SUBSCRIPTIONS @@ -1069,20 +1224,22 @@ component extends="cborm.models.VirtualEntityService" singleton { // recurse on them and inflate hiearchy for ( var thisSubscription in thisContent.commentSubscriptions ) { // Subscription - var oSubscription = variables.commentSubscriptionService.new( { - relatedContent : oContent, - subscriptionToken : thisSubscription.subscriptionToken, - type : thisSubscription.type - } ); + var oSubscription = variables.commentSubscriptionService.new( + { + relatedContent : oContent, + subscriptionToken: thisSubscription.subscriptionToken, + type : thisSubscription.type + } + ); // Subscriber - var oSubscriber = variables.subscriberService.findBySubscriberEmail( - thisSubscription.subscriber.subscriberEmail - ); + var oSubscriber = variables.subscriberService.findBySubscriberEmail( thisSubscription.subscriber.subscriberEmail ); if ( isNull( oSubscriber ) ) { - oSubscriber = variables.subscriberService.new( { - subscriberEmail : thisSubscription.subscriber.subscriberEmail, - subscriberToken : thisSubscription.subscriber.subscriberToken - } ); + oSubscriber = variables.subscriberService.new( + { + subscriberEmail: thisSubscription.subscriber.subscriberEmail, + subscriberToken: thisSubscription.subscriber.subscriberToken + } + ); } oSubscriber.addSubscription( oSubscription ); oSubscription.setSubscriber( oSubscriber ); @@ -1095,7 +1252,9 @@ component extends="cborm.models.VirtualEntityService" singleton { ); } // oContent.setCommentSubscriptions( allSubscriptions ); - logThis( "+ Content comment subscriptions imported to: (#thisContent.contentType#:#thisContent.slug#)" ); + logThis( + "+ Content comment subscriptions imported to: (#thisContent.contentType#:#thisContent.slug#)" + ); } // CONTENT VERSIONS @@ -1104,20 +1263,24 @@ component extends="cborm.models.VirtualEntityService" singleton { "+ Content versions (#arrayLen( thisContent.contentversions )#) found, about to start import for : (#thisContent.contentType#:#thisContent.slug#)" ); oContent.setContentVersions( - thisContent.contentVersions.map( function( thisVersion ){ - logThis( - "+ Importing content version (#thisVersion.version#) to : (#thisContent.contentType#:#thisContent.slug#)" - ); - var oVersion = getBeanPopulator().populateFromStruct( - target = variables.contentVersionService.new(), - memento = thisVersion, - exclude = "contentVersionID,author", - composeRelationships = false - ); - var oEditor = variables.authorService.findByEmail( thisVersion.author.email ); - return oVersion.setAuthor( isNull( oEditor ) ? oAuthor : oEditor ).setRelatedContent( oContent ); - } ) - ); + thisContent.contentVersions.map( + function( thisVersion ) { + logThis( + "+ Importing content version (#thisVersion.version#) to : (#thisContent.contentType#:#thisContent.slug#)" + ); + var oVersion = getBeanPopulator().populateFromStruct( + target = variables.contentVersionService.new(), + memento = thisVersion, + exclude = "contentVersionID,author", + composeRelationships = false + ); + var oEditor = variables.authorService.findByEmail( thisVersion.author.email ); + return oVersion.setAuthor( + isNull( oEditor ) ? oAuthor : oEditor + ).setRelatedContent( oContent ); + } + ) + ); } return oContent; @@ -1129,7 +1292,7 @@ component extends="cborm.models.VirtualEntityService" singleton { * @content A content object or id to update the hits on * @async Async or not */ - ContentService function updateHits( required content, boolean async = true ){ + ContentService function updateHits( required content, boolean async = true ) { // Inflate it if it's just an ID if ( isSimpleValue( arguments.content ) ) { arguments.content = get( arguments.content ); @@ -1142,7 +1305,7 @@ component extends="cborm.models.VirtualEntityService" singleton { /** * Returns an array of slugs of all the content objects in the system. */ - array function getAllFlatSlugs(){ + array function getAllFlatSlugs() { var c = newCriteria(); return c.withProjections( property = "slug" ).list( sortOrder = "slug asc" ); @@ -1159,25 +1322,25 @@ component extends="cborm.models.VirtualEntityService" singleton { * @return Array of content data {contentID, title, slug, createdDate, modifiedDate} */ array function getAllFlatContent( - sortOrder = "title asc", + sortOrder = "title asc", boolean isPublished, boolean showInSearch, string siteID = "", string contentType = "" - ){ + ) { var c = newCriteria(); // only published content - if ( - structKeyExists( arguments, "isPublished" ) - && - isBoolean( arguments.isPublished ) - ) { + if ( structKeyExists( arguments, "isPublished" ) && isBoolean( arguments.isPublished ) ) { // Published bit - c.isEq( "isPublished", javacast( "Boolean", arguments.isPublished ) ); + c.isEq( + "isPublished", + javacast( "Boolean", arguments.isPublished ) + ); // Published eq true evaluate other params if ( arguments.isPublished ) { - c.isLt( "publishedDate", now() ) + c + .isLt( "publishedDate", now() ) .$or( c.restrictions.isNull( "expireDate" ), c.restrictions.isGT( "expireDate", now() ) ) .isEq( "passwordProtection", "" ); } @@ -1193,17 +1356,18 @@ component extends="cborm.models.VirtualEntityService" singleton { } // Show in Search - if ( - structKeyExists( arguments, "showInSearch" ) - && - isBoolean( arguments.showInSearch ) - ) { + if ( structKeyExists( arguments, "showInSearch" ) && isBoolean( arguments.showInSearch ) ) { // showInSearch bit - c.isEq( "showInSearch", javacast( "Boolean", arguments.showInSearch ) ); + c.isEq( + "showInSearch", + javacast( "Boolean", arguments.showInSearch ) + ); } return c - .withProjections( property = "contentID,title,slug,createdDate,modifiedDate" ) + .withProjections( + property = "contentID,title,slug,createdDate,modifiedDate" + ) .asStruct() .list( sortOrder = arguments.sortOrder ); } @@ -1214,7 +1378,10 @@ component extends="cborm.models.VirtualEntityService" singleton { * @contentItem the target to relocate to * @originalSlug the URI from which to redirect */ - function addRelocation( required BaseContent contentItem, required string originalSlug ){ + function addRelocation( + required BaseContent contentItem, + required string originalSlug + ) { variables.relocationService.createContentRelocation( argumentCollection = arguments ); return this; } @@ -1227,7 +1394,7 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @type The content type to detect */ - private function getServiceByType( required type ){ + private function getServiceByType( required type ) { switch ( arguments.type ) { case "Page": return variables.pageService; @@ -1241,13 +1408,14 @@ component extends="cborm.models.VirtualEntityService" singleton { } return this; } + /** * Get a unique slug hash * * @slug The slug to unique it */ - private function getUniqueSlugHash( required string slug ){ + private function getUniqueSlugHash( required string slug ) { return "#arguments.slug#-#lCase( left( hash( now() ), 5 ) )#"; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/ContentStore.cfc b/modules/contentbox/models/content/ContentStore.cfc index ab41c611e8..2b98f6244f 100755 --- a/modules/contentbox/models/content/ContentStore.cfc +++ b/modules/contentbox/models/content/ContentStore.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -16,45 +16,43 @@ component joinColumn ="contentID" discriminatorValue="ContentStore" { - - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ /** * The internal description of the contentstore item */ property - name ="description" - column ="description" + name="description" + column="description" notnull="false" - length ="500" + length="500" default=""; /** * The ordering numeric sequence */ property - name ="order" - column ="order" - notnull ="false" - ormtype ="integer" - default ="0" + name="order" + column="order" + notnull="false" + ormtype="integer" + default="0" dbdefault="0"; + /********************************************************************** + * ** CONSTRAINTS + **********************************************************************/ - /* ********************************************************************* - ** CONSTRAINTS - ********************************************************************* */ - - this.constraints[ "description" ] = { required : false, size : "1..500" }; - this.constraints[ "order" ] = { required : false, type : "numeric" }; + this.constraints[ "description" ] = { required: false, size: "1..500" }; + this.constraints[ "order" ] = { required: false, type: "numeric" }; - /* ********************************************************************* - ** CONSTRUCTOR - ********************************************************************* */ + /********************************************************************** + * ** CONSTRUCTOR + **********************************************************************/ - function init(){ - var props = [ "description", "order" ]; + function init() { + var props = [ "description", "order"]; appendToMemento( props, "defaultIncludes" ); appendToMemento( [], "defaultExcludes" ); appendToMementoProfile( props, "export" ); @@ -62,21 +60,21 @@ component super.init(); - variables.categories = []; - variables.customFields = []; + variables.categories = []; + variables.customFields = []; variables.renderedContent = ""; - variables.allowComments = false; - variables.description = ""; - variables.createdDate = now(); - variables.contentType = "ContentStore"; - variables.order = 0; + variables.allowComments = false; + variables.description = ""; + variables.createdDate = now(); + variables.contentType = "ContentStore"; + variables.order = 0; return this; } - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ /** * Wipe primary key, and descendant keys, and prepare for cloning of entire hierarchies @@ -95,7 +93,7 @@ component required boolean publish, required any originalSlugRoot, required any newSlugRoot - ){ + ) { // original cloning! setDescription( arguments.original.getDescription() ); setOrder( arguments.original.getOrder() + 1 ); @@ -103,4 +101,4 @@ component return super.clone( argumentCollection = arguments ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/ContentStoreService.cfc b/modules/contentbox/models/content/ContentStoreService.cfc index e68ea18a7c..660fb22ca7 100755 --- a/modules/contentbox/models/content/ContentStoreService.cfc +++ b/modules/contentbox/models/content/ContentStoreService.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -6,14 +6,13 @@ * Manages content store items */ component extends="ContentService" singleton { - // DI property name="contentService" inject="id:ContentService@contentbox"; /** * Constructor */ - ContentStoreService function init(){ + ContentStoreService function init() { // init it super.init( entityName = "cbContentStore", useQueryCaching = true ); @@ -29,22 +28,22 @@ component extends="ContentService" singleton { * * @return ContentStoreService */ - function save( required any content, string originalSlug = "" ){ + function save( required any content, string originalSlug = "" ) { transaction { // save entry super.save( arguments.content ); // Update all affected child pages if any on slug updates, much like nested set updates its nodes, we update our slugs - if ( structKeyExists( arguments, "originalSlug" ) AND len( arguments.originalSlug ) ) { + if ( structKeyExists( arguments, "originalSlug" ) && len( arguments.originalSlug ) ) { var entriesInNeed = newCriteria().like( "slug", "#arguments.originalSlug#/%" ).list(); for ( var thisContent in entriesInNeed ) { thisContent.setSlug( - replaceNoCase( - thisContent.getSlug(), - arguments.originalSlug, - arguments.content.getSlug() - ) - ); + replaceNoCase( + thisContent.getSlug(), + arguments.originalSlug, + arguments.content.getSlug() + ) + ); super.save( thisContent ); } } @@ -74,10 +73,10 @@ component extends="ContentService" singleton { * @return struct = { content, count } */ struct function search( - string search = "", - string isPublished = "any", - string author = "all", - string creator = "all", + string search = "", + string isPublished = "any", + string author = "all", + string creator = "all", string parent, string category = "all", numeric max = 0, @@ -88,22 +87,21 @@ component extends="ContentService" singleton { string slugPrefix = "", string siteID = "", string propertyList - ){ - var results = { "count" : 0, "content" : [] }; + ) { + var results = { "count": 0, "content": [] }; // criteria queries - var c = newCriteria(); + var c = newCriteria(); // stub out activeContent alias based on potential conditions... // this way, we don't have to worry about accidentally creating it twice, or not creating it at all if ( - ( arguments.author NEQ "all" ) || - ( len( arguments.search ) ) || - ( findNoCase( "modifiedDate", arguments.sortOrder ) ) + ( arguments.author NEQ "all" ) || ( len( arguments.search ) ) || + ( findNoCase( "modifiedDate", arguments.sortOrder ) ) ) { c.createAlias( - associationName: "contentVersions", - alias : "ac", - withClause : getRestrictions().isTrue( "ac.isActive" ) - ); + associationName = "contentVersions", + alias = "ac", + withClause = getRestrictions().isTrue( "ac.isActive" ) + ); } // only search shownInSearch bits @@ -113,7 +111,10 @@ component extends="ContentService" singleton { // isPublished filter if ( arguments.isPublished NEQ "any" ) { - c.isEq( "isPublished", javacast( "boolean", arguments.isPublished ) ); + c.isEq( + "isPublished", + javacast( "boolean", arguments.isPublished ) + ); } // Author Filter @@ -137,23 +138,23 @@ component extends="ContentService" singleton { if ( arguments.searchActiveContent ) { // like disjunctions c.$or( - c.restrictions.like( "title", "%#arguments.search#%" ), - c.restrictions.like( "slug", "%#arguments.search#%" ), - c.restrictions.like( "description", "%#arguments.search#%" ), - c.restrictions.like( "ac.content", "%#arguments.search#%" ) - ); + c.restrictions.like( "title", "%#arguments.search#%" ), + c.restrictions.like( "slug", "%#arguments.search#%" ), + c.restrictions.like( "description", "%#arguments.search#%" ), + c.restrictions.like( "ac.content", "%#arguments.search#%" ) + ); } else { c.$or( - c.restrictions.like( "title", "%#arguments.search#%" ), - c.restrictions.like( "slug", "%#arguments.search#%" ), - c.restrictions.like( "description", "%#arguments.search#%" ) - ); + c.restrictions.like( "title", "%#arguments.search#%" ), + c.restrictions.like( "slug", "%#arguments.search#%" ), + c.restrictions.like( "description", "%#arguments.search#%" ) + ); } } // parent filter if ( !isNull( arguments.parent ) ) { - if ( isSimpleValue( arguments.parent ) and len( arguments.parent ) ) { + if ( isSimpleValue( arguments.parent ) && len( arguments.parent ) ) { c.isEq( "parent.contentID", arguments.parent ); } else if ( isObject( arguments.parent ) ) { c.isEq( "parent", arguments.parent ); @@ -170,13 +171,12 @@ component extends="ContentService" singleton { // Category Filter if ( arguments.category NEQ "all" ) { // Uncategorized? - if ( arguments.category eq "none" ) { + if ( arguments.category EQ "none" ) { c.isEmpty( "categories" ); - } - // With categories - else { + } else { + // With categories // search the association - c.createAlias( "categories", "cats" ).isIn( "cats.categoryID", [ arguments.category ] ); + c.createAlias( "categories", "cats" ).isIn( "cats.categoryID", [ arguments.category] ); } } @@ -188,9 +188,8 @@ component extends="ContentService" singleton { "modifiedDate", "ac.createdDate" ); - } - // default to title sorting - else if ( !len( arguments.sortOrder ) ) { + } else if ( !len( arguments.sortOrder ) ) { + // default to title sorting sortOrder = "title asc"; } @@ -203,11 +202,11 @@ component extends="ContentService" singleton { c.resultTransformer( c.DISTINCT_ROOT_ENTITY ); } results.content = c.list( - offset : arguments.offset, - max : arguments.max, - sortOrder: arguments.sortOrder, - asQuery : false - ); + offset = arguments.offset, + max = arguments.max, + sortOrder = arguments.sortOrder, + asQuery = false + ); return results; } @@ -216,13 +215,11 @@ component extends="ContentService" singleton { * * @site The site to get the export from */ - array function getAllForExport( required site ){ - return super.getAllForExport( - newCriteria() - .isNull( "parent" ) - .isEq( "site", arguments.site ) - .list() - ); + array function getAllForExport( required site ) { + return super.getAllForExport( newCriteria() + .isNull( "parent" ) + .isEq( "site", arguments.site ) + .list() ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/ContentTemplate.cfc b/modules/contentbox/models/content/ContentTemplate.cfc index af8ff886e7..2500d8852c 100644 --- a/modules/contentbox/models/content/ContentTemplate.cfc +++ b/modules/contentbox/models/content/ContentTemplate.cfc @@ -13,11 +13,11 @@ component cachename ="cbContentTemplate" cacheuse ="read-write" { - property - name ="contentTemplateService" - inject ="provider:ContentTemplateService@contentbox" + name="contentTemplateService" + inject="provider:ContentTemplateService@contentbox" persistent="false"; + /** * -------------------------------------------------------------------------- * STUPID PROPERTIES DUE TO ACF BUG @@ -26,30 +26,30 @@ component * has never been fixed. Until it does, keep these. */ property - name ="createdDate" - column ="createdDate" - type ="date" + name="createdDate" + column="createdDate" + type="date" ormtype="timestamp" notnull="true" - update ="false"; + update="false"; property - name ="modifiedDate" - column ="modifiedDate" - type ="date" + name="modifiedDate" + column="modifiedDate" + type="date" ormtype="timestamp" notnull="true"; property - name ="isDeleted" - column ="isDeleted" + name="isDeleted" + column="isDeleted" ormtype="boolean" notnull="true" default="false"; property - name ="isGlobal" - column ="isGlobal" + name="isGlobal" + column="isGlobal" ormtype="boolean" notnull="true" default="false"; @@ -61,66 +61,65 @@ component */ property - name ="templateID" - column ="templateID" + name="templateID" + column="templateID" fieldtype="id" generator="uuid" - length ="36" - ormtype ="string" - update ="false"; + length="36" + ormtype="string" + update="false"; // The content type to restrict this template to. If left blank, all content types are eligible property - name ="contentType" - column ="contentType" - length ="50" + name="contentType" + column="contentType" + length="50" default="" - index ="idx_templateContentType"; + index="idx_templateContentType"; property - name ="name" - column ="name" + name="name" + column="name" notnull="true" - length ="225" + length="225" default=""; property - name ="description" - column ="description" + name="description" + column="description" notnull="false" - length ="1000"; + length="1000"; property - name ="definition" - column ="definition" + name="definition" + column="definition" notnull="true" ormtype="text" default="{}"; // M20 -> creator loaded as a proxy and fetched immediately property - name ="creator" - notnull ="true" - cfc ="contentbox.models.security.Author" + name="creator" + notnull="true" + cfc="contentbox.models.security.Author" fieldtype="many-to-one" - fkcolumn ="FK_authorID" - insert =true - update =false; + fkcolumn="FK_authorID" + insert=true + update=false; // M20 -> site loaded as a proxy and fetched immediately property - name ="site" - notnull ="true" - cfc ="contentbox.models.system.Site" + name="site" + notnull="true" + cfc="contentbox.models.system.Site" fieldtype="many-to-one" - fkcolumn ="FK_siteID" - lazy ="true" - insert =true - update =false; - + fkcolumn="FK_siteID" + lazy="true" + insert=true + update=false; property - name ="assignedContentItems" + name="assignedContentItems" ormtype="integer" default=0 formula="select count(*) from cb_content cbc2 WHERE cbc2.FK_contentTemplateID=templateID or cbc2.FK_childContentTemplateID=templateID"; @@ -128,144 +127,143 @@ component // The non-persistent schema of the JSON definition property name="schema" persistent="false"; - - function init(){ - variables.createdDate = now(); + function init() { + variables.createdDate = now(); variables.modifiedDate = now(); - variables.schema = { - "title" : { "label" : "Title", "type" : "string", "sortOrder" : 1 }, - "content" : { "label" : "Content", "type" : "text", "sortOrder" : 2 }, - "markup" : { "label" : "Markup", "type" : "markdown", "sortOrder" : 3 }, - "description" : { - "label" : "Description", - "type" : "text", - "excludeTypes" : [ "Page", "Entry" ], - "sortOrder" : 4 + variables.schema = { + "title" : { "label": "Title", "type": "string", "sortOrder": 1 }, + "content" : { "label": "Content", "type": "text", "sortOrder": 2 }, + "markup" : { "label": "Markup", "type": "markdown", "sortOrder": 3 }, + "description": { + "label" : "Description", + "type" : "text", + "excludeTypes": [ "Page", "Entry"], + "sortOrder" : 4 }, - "excerpt" : { - "label" : "Excerpt", - "type" : "text", - "excludeTypes" : [ "ContentStore" ], - "sortOrder" : 5 + "excerpt": { + "label" : "Excerpt", + "type" : "text", + "excludeTypes": [ "ContentStore"], + "sortOrder" : 5 }, - "featuredImage" : { - "label" : "Featured Image", - "type" : "file", - "sortOrder" : 6 + "featuredImage": { + "label" : "Featured Image", + "type" : "file", + "sortOrder": 6 }, // SEO - "HTMLTitle" : { - "label" : "HTML Title", - "type" : "string", - "excludeTypes" : [ "ContentStore" ], - "sortOrder" : 7 + "HTMLTitle": { + "label" : "HTML Title", + "type" : "string", + "excludeTypes": [ "ContentStore"], + "sortOrder" : 7 }, - "HTMLKeywords" : { - "label" : "HTML Keywords", - "type" : "string", - "excludeTypes" : [ "ContentStore" ], - "sortOrder" : 8 + "HTMLKeywords": { + "label" : "HTML Keywords", + "type" : "string", + "excludeTypes": [ "ContentStore"], + "sortOrder" : 8 }, - "HTMLDescription" : { - "label" : "HTML Description", - "type" : "text", - "excludeTypes" : [ "ContentStore" ], - "sortOrder" : 9 + "HTMLDescription": { + "label" : "HTML Description", + "type" : "text", + "excludeTypes": [ "ContentStore"], + "sortOrder" : 9 }, // Modifiers - "parent" : { - "label" : "Content Parent", - "type" : "typeahead", - "search" : "/cbapi/v1/sites/:siteId/pages", - "options" : "filteredParents", - "optionId" : "contentID", - "optionLabel" : "title", - "excludeTypes" : [ "Entry" ], - "sortOrder" : 10 + "parent": { + "label" : "Content Parent", + "type" : "typeahead", + "search" : "/cbapi/v1/sites/:siteId/pages", + "options" : "filteredParents", + "optionId" : "contentID", + "optionLabel" : "title", + "excludeTypes": [ "Entry"], + "sortOrder" : 10 }, // Collections - "customFields" : { - "label" : "Custom Fields", - "type" : "array", - "schema" : { - "name" : { - "label" : "Field Name", - "required" : true, - "type" : "string" + "customFields": { + "label" : "Custom Fields", + "type" : "array", + "schema": { + "name": { + "label" : "Field Name", + "required": true, + "type" : "string" }, - "defaultValue" : { "label" : "Default Value", "type" : "string" } + "defaultValue": { "label": "Default Value", "type": "string" } }, - "presentation" : "input", - "sortOrder" : 11 + "presentation": "input", + "sortOrder" : 11 }, - "categories" : { - "label" : "Assigned Categories", - "type" : "select", - "options" : "availableCategories", - "multiple" : true, - "sortOrder" : 12 + "categories": { + "label" : "Assigned Categories", + "type" : "select", + "options" : "availableCategories", + "multiple" : true, + "sortOrder": 12 }, - "childContentTemplate" : { - "label" : "Child Template", - "type" : "select", - "options" : "availableTemplates", - "excludeTypes" : [ "Entry" ], - "sortOrder" : 13 + "childContentTemplate": { + "label" : "Child Template", + "type" : "select", + "options" : "availableTemplates", + "excludeTypes": [ "Entry"], + "sortOrder" : 13 }, // Layout options - "layout" : { - "label" : "Layout", - "type" : "select", - "options" : "availableLayouts", - "excludeTypes" : [ "ContentStore", "Entry" ], - "sortOrder" : 14 + "layout": { + "label" : "Layout", + "type" : "select", + "options" : "availableLayouts", + "excludeTypes": [ "ContentStore", "Entry"], + "sortOrder" : 14 }, // Caching - "cache" : { - "label" : "Cache Enabled", - "type" : "boolean", - "default" : true, - "sortOrder" : 15 + "cache": { + "label" : "Cache Enabled", + "type" : "boolean", + "default" : true, + "sortOrder": 15 }, - "cacheTimeout" : { - "label" : "Cache Timeout", - "type" : "integer", - "default" : 0, - "sortOrder" : 16 + "cacheTimeout": { + "label" : "Cache Timeout", + "type" : "integer", + "default" : 0, + "sortOrder": 16 }, - "cacheLastAccessTimeout" : { - "label" : "Cache Last Access Timeout", - "type" : "integer", - "default" : 0, - "sortOrder" : 17 + "cacheLastAccessTimeout": { + "label" : "Cache Last Access Timeout", + "type" : "integer", + "default" : 0, + "sortOrder": 17 }, - "passwordProtection" : { - "label" : "Access Password", - "type" : "string", - "excludeTypes" : [ "ContentStore" ], - "sortOrder" : 18 + "passwordProtection": { + "label" : "Access Password", + "type" : "string", + "excludeTypes": [ "ContentStore"], + "sortOrder" : 18 }, - "allowComments" : { - "label" : "Comments Enabled", - "type" : "boolean", - "default" : true, - "excludeTypes" : [ "ContentStore" ], - "sortOrder" : 19 + "allowComments": { + "label" : "Comments Enabled", + "type" : "boolean", + "default" : true, + "excludeTypes": [ "ContentStore"], + "sortOrder" : 19 }, // Display Options - "showInMenu" : { - "label" : "Show In Menu", - "type" : "boolean", - "default" : true, - "excludeTypes" : [ "ContentStore", "Entry" ], - "sortOrder" : 20 + "showInMenu": { + "label" : "Show In Menu", + "type" : "boolean", + "default" : true, + "excludeTypes": [ "ContentStore", "Entry"], + "sortOrder" : 20 }, - "showInSearch" : { - "label" : "Show In Search", - "type" : "boolean", - "default" : true, - "excludeTypes" : [ "ContentStore" ], - "sortOrder" : 21 + "showInSearch": { + "label" : "Show In Search", + "type" : "boolean", + "default" : true, + "excludeTypes": [ "ContentStore"], + "sortOrder" : 21 } }; @@ -273,7 +271,7 @@ component } this.memento = { - "defaultIncludes" : [ + "defaultIncludes": [ "templateID", "contentType", "name", @@ -282,9 +280,9 @@ component "definition", "assignedContentItems" ], - profiles : { - export : { - defaultIncludes : [ + profiles: { + export: { + defaultIncludes: [ "templateID", "contentType", "name", @@ -293,38 +291,37 @@ component "createdDate", "modifiedDate" ], - defaultExcludes : [ "assignedContentItems", "site", "creator" ] + defaultExcludes: [ "assignedContentItems", "site", "creator"] } }, - mappers : { - "assignedContentItems" : function( target, value ){ - return javacast( "int", arguments.target ) + mappers: { + "assignedContentItems": function( target, value ) { + return javacast( "int", arguments.target ); } } }; this.constraints = { - "name" : { - required : true, - size : "1..200", - "udf" : ( value, target ) => target.isNameUniqueInSite( value ) + "name": { + required: true, + size : "1..200", + "udf" : ( value, target ) => target.isNameUniqueInSite( value ) }, - "definition" : { required : true }, - "site" : { required : true }, - "isGlobal" : { - required : true, - "udf" : ( value, target ) => target.isGlobalUniqueInSite( value ), - "udfMessage" : "A site may only have one global template per content type. If you wish to make this template global, please deactivate the existing global template." + "definition": { required: true }, + "site" : { required: true }, + "isGlobal" : { + required : true, + "udf" : ( value, target ) => target.isGlobalUniqueInSite( value ), + "udfMessage": "A site may only have one global template per content type. If you wish to make this template global, please deactivate the existing global template." } }; - /** * Overload getter for definition to deal with JSON conversion * * @overload */ - function getDefinition(){ + function getDefinition() { return deserializeJSON( variables.definition ); } @@ -333,14 +330,14 @@ component * * @overload */ - function setDefinition( definition ){ + function setDefinition( definition ) { variables.definition = isSimpleValue( arguments.definition ) - ? arguments.definition - : serializeJSON( - arguments.definition, - false, - listFindNoCase( "Lucee", server.coldfusion.productname ) ? "utf-8" : false - ); + ? arguments.definition + : serializeJSON( + arguments.definition, + false, + listFindNoCase( "Lucee", server.coldfusion.productname ) ? "utf-8" : false + ); return this; } @@ -349,7 +346,7 @@ component * * @value The name to test for uniqueness */ - boolean function isNameUniqueInSite( value = variables.name ){ + boolean function isNameUniqueInSite( value = variables.name ) { var c = getContentTemplateService() .newCriteria() .isEq( "site", getSite() ) @@ -365,8 +362,10 @@ component /** * UDF validation method to test for global uniqueness of a Content Template */ - boolean function isGlobalUniqueInSite(){ - if ( !variables.isGlobal ) return true; + boolean function isGlobalUniqueInSite() { + if ( !variables.isGlobal ) { + return true; + } var c = getContentTemplateService() .newCriteria() @@ -381,4 +380,4 @@ component return !c.count(); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/ContentTemplateService.cfc b/modules/contentbox/models/content/ContentTemplateService.cfc index 41af14e412..cbc2d2a112 100644 --- a/modules/contentbox/models/content/ContentTemplateService.cfc +++ b/modules/contentbox/models/content/ContentTemplateService.cfc @@ -6,15 +6,15 @@ * Template service for contentbox */ component extends="cborm.models.VirtualEntityService" singleton { - // Dependencies property name="dateUtil" inject="DateUtil@contentbox"; + property name="contentService" inject="ContentService@contentbox"; /** * Constructor */ - ContentTemplateService function init(){ + ContentTemplateService function init() { // init it super.init( entityName = "cbContentTemplate", useQueryCaching = true ); @@ -39,36 +39,43 @@ component extends="cborm.models.VirtualEntityService" singleton { max = 0, offset = 0, sortOrder = "name asc" - ){ - var results = { "count" : 0, "templates" : [] }; - var c = newCriteria() - // Site Filter - .when( len( arguments.siteID ), function( c ){ - c.isEq( "site.siteID", siteID ); - } ) + ) { + var results = { "count": 0, "templates": [] }; + var c = newCriteria().when( + len( arguments.siteID ), + function( c ) { + c.isEq( "site.siteID", siteID ); + } + )// Site Filter + // Search Criteria - .when( len( arguments.search ), function( c ){ - c.or( c.restrictions.like( "name", "%#search#%" ), c.restrictions.like( "description", "%#search#%" ) ); - } ); + .when( + len( arguments.search ), + function( c ) { + c.or( + c.restrictions.like( "name", "%#search#%" ), + c.restrictions.like( "description", "%#search#%" ) + ); + } + ); // run criteria query and projections count - results.count = c.count( "contentTemplateID" ); + results.count = c.count( "contentTemplateID" ); results.templates = c.list( - offset : arguments.offset, - max : arguments.max, - sortOrder: arguments.sortOrder - ); + offset = arguments.offset, + max = arguments.max, + sortOrder = arguments.sortOrder + ); return results; } - /** * Delete a template which also removes itself from all many-to-many relationships * * @template The template object to remove from the system */ - boolean function delete( required template ){ + boolean function delete( required template ) { transaction { // Remove content relationships var assignedContent = removeTemplateAssignments( arguments.template ); @@ -91,24 +98,28 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @template The template object */ - array function removeTemplateAssignments( required template ){ + array function removeTemplateAssignments( required template ) { var assignedContent = contentService .newCriteria() .isEq( "contentTemplate", arguments.template ) .list(); - assignedContent.each( function( contentItem ){ - contentItem.setContentTemplate( javacast( "null", 0 ) ); - } ); + assignedContent.each( + function( contentItem ) { + contentItem.setContentTemplate( javacast( "null", 0 ) ); + } + ); var childrenAssignments = contentService .newCriteria() .isEq( "childContentTemplate", arguments.template ) .list(); - childrenAssignments.each( function( contentItem ){ - contentItem.setChildContentTemplate( javacast( "null", 0 ) ); - } ); + childrenAssignments.each( + function( contentItem ) { + contentItem.setChildContentTemplate( javacast( "null", 0 ) ); + } + ); assignedContent.append( childrenAssignments, true ); @@ -126,7 +137,7 @@ component extends="cborm.models.VirtualEntityService" singleton { required string contentType, required Site site, string fields - ){ + ) { if ( isNull( arguments.site ) ) { arguments.site = getWirebox().getInstance( "cbHelper@ContentBox" ).site(); } @@ -144,79 +155,86 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @site The site to export from */ - array function getAllForExport( required site ){ - return findAllWhere( { site : arguments.site } ).map( function( thisItem ){ - return thisItem.getMemento( profile: "export" ); - } ); + array function getAllForExport( required site ) { + return findAllWhere( { site: arguments.site } ).map( + function( thisItem ) { + return thisItem.getMemento( profile = "export" ); + } + ); } - ContentTemplate function newFromContentItem( required BaseContent contentItem ){ - var newTemplate = new ( + ContentTemplate function newFromContentItem( required BaseContent contentItem ) { + var newTemplate = new( properties = { - "site" : arguments.contentItem.getSite(), - "name" : arguments.contentItem.getTitle(), - "contentType" : arguments.contentItem.getContentType(), - "description" : "Template automatically created from " & arguments.contentItem.getContentType() & " " & arguments.contentItem.getTitle(), - "creator" : arguments.contentItem.getCreator() + "site" : arguments.contentItem.getSite(), + "name" : arguments.contentItem.getTitle(), + "contentType": arguments.contentItem.getContentType(), + "description": "Template automatically created from " & arguments.contentItem.getContentType() & " " & arguments.contentItem.getTitle(), + "creator" : arguments.contentItem.getCreator() } ); - var schema = newTemplate.getSchema(); - var templateProperties = schema - .keyArray() - .filter( function( key ){ - return !schema[ key ].keyExists( "excludeTypes" ) || !schema[ key ].excludeTypes.contains( - contentItem.getContentType() - ) - } ); - - var definition = templateProperties.reduce( function( acc, key ){ - switch ( key ) { - case "customFields": { - if ( arrayLen( contentItem.getCustomFields() ) ) { - acc[ key ] = { "value" : [] }; - contentItem - .getCustomFields() - .each( function( field ){ - acc[ key ].value.append( { - "name" : field.getKey(), - "defaultValue" : field.getValue() - } ); - } ); - } - break; - } - case "categories": { - if ( arrayLen( contentItem.getCategories() ) ) { - acc[ key ] = { - "value" : contentItem - .getCategories() - .map( function( cat ){ - return cat.getCategoryID(); - } ) - }; - } - break; - } - case "parent": { - if ( !isNull( contentItem.getParent() ) ) { - acc[ key ] = { "value" : contentItem.getParent.getContentID() }; - } - break; + var schema = newTemplate.getSchema(); + var templateProperties = schema.keyArray().filter( + function( key ) { + return !schema[ key ].keyExists( "excludeTypes" ) || + !schema[ key ].excludeTypes.contains( contentItem.getContentType() ); } - default: { - var val = invoke( contentItem, "get" & key ); - if ( !isNull( val ) && isSimpleValue( val ) && len( val ) ) { - acc[ key ] = { "value" : val }; - if ( !isNumeric( acc[ key ].value ) && isBoolean( acc[ key ].value ) ) - acc[ key ].value = javacast( "boolean", true ); + ); + + var definition = templateProperties.reduce( + function( acc, key ) { + switch ( key ) { + case "customFields": { + if ( arrayLen( contentItem.getCustomFields() ) ) { + acc[ key ] = { "value": [] }; + contentItem.getCustomFields().each( + function( field ) { + acc[ key ].value.append( + { + "name" : field.getKey(), + "defaultValue": field.getValue() + } + ); + } + ); + } + break; + } + case "categories": { + if ( arrayLen( contentItem.getCategories() ) ) { + acc[ key ] = { + "value": contentItem.getCategories().map( + function( cat ) { + return cat.getCategoryID(); + } + ) + }; + } + break; + } + case "parent": { + if ( !isNull( contentItem.getParent() ) ) { + acc[ key ] = { "value": contentItem.getParent.getContentID() }; + } + break; + } + default: { + var val = invoke( contentItem, "get" & key ); + if ( !isNull( val ) && isSimpleValue( val ) && len( val ) ) { + acc[ key ] = { "value": val }; + if ( !isNumeric( acc[ key ].value ) && isBoolean( acc[ key ].value ) ) { + acc[ key ].value = javacast( "boolean", true ); + } + } + } } - } - } - return acc; - }, {} ); + return acc; + }, + {} + ); newTemplate.setDefinition( definition ); return newTemplate; - }; + } /** * Import data from a ContentBox JSON file. Returns the import log @@ -228,14 +246,17 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @throws InvalidImportFormat */ - string function importFromFile( required importFile, boolean override = false ){ - var data = fileRead( arguments.importFile ); + string function importFromFile( required importFile, boolean override = false ) { + var data = fileRead( arguments.importFile ); var importLog = createObject( "java", "java.lang.StringBuilder" ).init( - "Starting import with override = #arguments.override#...
" - ); + "Starting import with override = #arguments.override#...
" + ); if ( !isJSON( data ) ) { - throw( message = "Cannot import file as the contents is not JSON", type = "InvalidImportFormat" ); + throw( + message = "Cannot import file as the contents is not JSON", + type = "InvalidImportFormat" + ); } // deserialize packet: Should be array of { settingID, name, value } @@ -261,13 +282,13 @@ component extends="cborm.models.VirtualEntityService" singleton { required importData, boolean override = false, importLog - ){ + ) { var allTemplates = []; - var siteService = getWireBox().getInstance( "siteService@contentbox" ); + var siteService = getWireBox().getInstance( "siteService@contentbox" ); // if struct, inflate into an array if ( isStruct( arguments.importData ) ) { - arguments.importData = [ arguments.importData ]; + arguments.importData = [ arguments.importData]; } transaction { @@ -275,16 +296,16 @@ component extends="cborm.models.VirtualEntityService" singleton { for ( var thisTemplate in arguments.importData ) { var assignedSite = siteService.getBySlugOrFail( thisTemplate.site.slug ); // Get new or persisted - var oTemplate = this.findBySiteAndName( site = assignedSite, name = thisTemplate.site.name ); - oTemplate = ( isNull( oTemplate ) ? new () : oTemplate ); + var oTemplate = this.findBySiteAndName( site = assignedSite, name = thisTemplate.site.name ); + oTemplate = ( isNull( oTemplate ) ? new() : oTemplate ); // populate content from data getBeanPopulator().populateFromStruct( - target : oTemplate, - memento : thisTemplate, - exclude : "templateID", - composeRelationships: false - ); + target = oTemplate, + memento = thisTemplate, + exclude = "templateID", + composeRelationships = false + ); // Link the site oTemplate.setSite( assignedSite ); @@ -292,18 +313,18 @@ component extends="cborm.models.VirtualEntityService" singleton { // if new or persisted with override then save. if ( !oTemplate.isLoaded() ) { arguments.importLog.append( - "New template imported for site #assignedSite.getName()#: #thisTemplate.name#
" - ); + "New template imported for site #assignedSite.getName()#: #thisTemplate.name#
" + ); arrayAppend( allTemplates, oTemplate ); - } else if ( oTemplate.isLoaded() and arguments.override ) { + } else if ( oTemplate.isLoaded() && arguments.override ) { arguments.importLog.append( - "Persisted template overriden for site #assignedSite.getName()#: #thisTemplate.name#
" - ); + "Persisted template overriden for site #assignedSite.getName()#: #thisTemplate.name#
" + ); arrayAppend( allTemplates, oTemplate ); } else { arguments.importLog.append( - "Skipping persisted template for site #assignedSite.getName()#: #thisTemplate.name#
" - ); + "Skipping persisted template for site #assignedSite.getName()#: #thisTemplate.name#
" + ); } } // end import loop @@ -314,12 +335,12 @@ component extends="cborm.models.VirtualEntityService" singleton { arguments.importLog.append( "Saved all imported and overriden templates!" ); } else { arguments.importLog.append( - "No templates imported as none where found or able to be overriden from the import file." - ); + "No templates imported as none where found or able to be overriden from the import file." + ); } } // end of transaction return arguments.importLog.toString(); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/ContentVersion.cfc b/modules/contentbox/models/content/ContentVersion.cfc index 95cdcbd5ab..a28cbe1111 100755 --- a/modules/contentbox/models/content/ContentVersion.cfc +++ b/modules/contentbox/models/content/ContentVersion.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -14,114 +14,106 @@ component cachename ="cbContentVersion" cacheuse ="read-write" { + /********************************************************************** + * ** DI + **********************************************************************/ - /* ********************************************************************* - ** DI - ********************************************************************* */ - - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="contentVersionID" - column ="contentVersionID" + name="contentVersionID" + column="contentVersionID" fieldtype="id" generator="uuid" - length ="36" - ormtype ="string" - update ="false"; + length="36" + ormtype="string" + update="false"; property - name ="content" - column ="content" + name="content" + column="content" notnull="true" ormtype="text" - length ="8000" + length="8000" default=""; property - name ="changelog" - column ="changelog" + name="changelog" + column="changelog" notnull="false" ormtype="text" - length ="8000" + length="8000" default=""; property - name ="version" - column ="version" + name="version" + column="version" notnull="true" ormtype="integer" default="1" - index ="idx_version"; + index="idx_version"; property - name ="isActive" - column ="isActive" + name="isActive" + column="isActive" notnull="true" ormtype="boolean" default="false" - index ="idx_activeContentVersion,idx_contentVersions"; + index="idx_activeContentVersion,idx_contentVersions"; - /* ********************************************************************* - ** RELATIONSHIPS - ********************************************************************* */ + /********************************************************************** + * ** RELATIONSHIPS + **********************************************************************/ // M20 -> Author loaded as a proxy and fetched immediately property - name ="author" - notnull ="true" - cfc ="contentbox.models.security.Author" + name="author" + notnull="true" + cfc="contentbox.models.security.Author" fieldtype="many-to-one" - fkcolumn ="FK_authorID" - fetch ="join"; + fkcolumn="FK_authorID" + fetch="join"; // M20 -> relatedContent property - name ="relatedContent" - notnull ="true" - cfc ="contentbox.models.content.BaseContent" + name="relatedContent" + notnull="true" + cfc="contentbox.models.content.BaseContent" fieldtype="many-to-one" - fkcolumn ="FK_contentID" - lazy ="true" - index ="idx_contentVersions"; + fkcolumn="FK_contentID" + lazy="true" + index="idx_contentVersions"; - /* ********************************************************************* - ** NON PERSISTED PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** NON PERSISTED PROPERTIES + **********************************************************************/ property name="renderedContent" persistent="false"; - - /* ********************************************************************* - ** PK + CONSTRAINTS - ********************************************************************* */ + /********************************************************************** + * ** PK + CONSTRAINTS + **********************************************************************/ this.pk = "contentVersionID"; this.memento = { - defaultIncludes : [ - "content", - "changelog", - "version", - "isActive", - "authorSnapshot:author" - ], - defaultExcludes : [ "relatedContent" ], - neverInclude : [ "" ] + defaultIncludes: [ "content", "changelog", "version", "isActive", "authorSnapshot:author"], + defaultExcludes: [ "relatedContent"], + neverInclude : [ ""] }; this.constraints = { - "content" : { required : true }, - "version" : { required : true, type : "integer" } + "content": { required: true }, + "version": { required: true, type: "integer" } }; - function init(){ - variables.createdDate = now(); - variables.isActive = false; - variables.version = 1; - variables.content = ""; - variables.changelog = ""; + function init() { + variables.createdDate = now(); + variables.isActive = false; + variables.version = 1; + variables.content = ""; + variables.changelog = ""; variables.renderedContent = ""; super.init(); @@ -132,14 +124,14 @@ component /** * Build the author snapshot */ - struct function getAuthorSnapshot(){ + struct function getAuthorSnapshot() { return ( hasAuthor() ? getAuthor().getInfoSnapshot() : {} ); } /** * Build a snapshot of the related content */ - struct function getRelatedContentSnapshot(){ + struct function getRelatedContentSnapshot() { if ( hasRelatedContent() ) { return getRelatedContent().getInfoSnapshot(); } @@ -149,7 +141,7 @@ component /** * Shorthand Author name */ - string function getAuthorName(){ + string function getAuthorName() { if ( hasAuthor() ) { return getAuthor().getFullName(); } @@ -159,7 +151,7 @@ component /** * Shorthand Author email */ - string function getAuthorEmail(){ + string function getAuthorEmail() { if ( hasAuthor() ) { return getAuthor().getEmail(); } @@ -169,7 +161,7 @@ component /** * Get parent slug from the related content it belongs to */ - function getParentSlug(){ + function getParentSlug() { if ( hasRelatedContent() ) { return getRelatedContent().getSlug(); } @@ -179,7 +171,7 @@ component /** * Get parent title from the related content it belongs to */ - function getParentTitle(){ + function getParentTitle() { if ( hasRelatedContent() ) { return getRelatedContent().getTitle(); } @@ -189,22 +181,23 @@ component /** * Render version content out */ - any function renderContent(){ + any function renderContent() { // Check if we need to translate - if ( NOT len( variables.renderedContent ) ) { + if ( !len( variables.renderedContent ) ) { lock name ="contentbox.versionrendering.#getContentVersionID()#" type ="exclusive" throwontimeout="true" - timeout ="10" { - if ( NOT len( variables.renderedContent ) ) { + timeout ="10" + { + if ( !len( variables.renderedContent ) ) { // else render content out, prepare builder var builder = createObject( "java", "java.lang.StringBuilder" ).init( variables.content ); // announce renderings with data, so content renderers can process them variables.interceptorService.announce( - "cb_onContentRendering", - { builder : builder, content : this } - ); + "cb_onContentRendering", + { builder: builder, content: this } + ); // save content variables.renderedContent = builder.toString(); @@ -216,4 +209,4 @@ component return variables.renderedContent; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/ContentVersionService.cfc b/modules/contentbox/models/content/ContentVersionService.cfc index eee95b5891..aa3dde280d 100755 --- a/modules/contentbox/models/content/ContentVersionService.cfc +++ b/modules/contentbox/models/content/ContentVersionService.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -10,7 +10,7 @@ component extends="cborm.models.VirtualEntityService" singleton { /** * Constructor */ - ContentVersionService function init(){ + ContentVersionService function init() { // init it super.init( entityName = "cbContentVersion" ); @@ -25,12 +25,15 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @return The number of versions a content object has by filters */ - numeric function getNumberOfVersions( string contentId = "", boolean isActive ){ + numeric function getNumberOfVersions( string contentId = "", boolean isActive ) { return newCriteria() .isEq( "relatedContent.contentID", arguments.contentId ) - .when( !isNull( arguments.isActive ), function( c ){ - c.isEq( "isActive", javacast( "Boolean", isActive ) ); - } ) + .when( + !isNull( arguments.isActive ), + function( c ) { + c.isEq( "isActive", javacast( "Boolean", isActive ) ); + } + ) .count(); } @@ -41,7 +44,7 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @return The active version if found, else a new ContentVersion object */ - function getActiveVersion( required contentId ){ + function getActiveVersion( required contentId ) { // Get all the active versions var aVersions = newCriteria() .isEq( "relatedContent.contentID", arguments.contentId ) @@ -65,22 +68,22 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @return struct of { count : numeric, versions : array} */ - struct function findRelatedVersions( required contentID, max = 0, offset = 0 ){ + struct function findRelatedVersions( required contentID, max = 0, offset = 0 ) { var results = {}; // Find it var c = newCriteria().isEq( "relatedContent.contentID", arguments.contentId ); // run criteria query and projections count - results.count = c.count(); + results.count = c.count(); results.versions = c.list( - offset = arguments.offset, - max = arguments.max, - sortOrder = "version DESC", - asQuery = false - ); + offset = arguments.offset, + max = arguments.max, + sortOrder = "version DESC", + asQuery = false + ); return results; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/CustomField.cfc b/modules/contentbox/models/content/CustomField.cfc index cc3b61224b..8cd566843a 100644 --- a/modules/contentbox/models/content/CustomField.cfc +++ b/modules/contentbox/models/content/CustomField.cfc @@ -13,71 +13,69 @@ component cachename ="cbCustomField" cacheuse ="read-write" { - - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="customFieldID" - column ="customFieldID" + name="customFieldID" + column="customFieldID" fieldtype="id" generator="uuid" - length ="36" - ormtype ="string" - update ="false"; + length="36" + ormtype="string" + update="false"; property - name ="key" - column ="key" + name="key" + column="key" notnull="true" ormtype="string" - length ="255"; + length="255"; property - name ="value" - column ="value" + name="value" + column="value" notnull="true" ormtype="text" - length ="8000"; + length="8000"; - /* ********************************************************************* - ** RELATIONSHIPS - ********************************************************************* */ + /********************************************************************** + * ** RELATIONSHIPS + **********************************************************************/ // M20 -> Content loaded as a proxy property - name ="relatedContent" - notnull ="false" - cfc ="contentbox.models.content.BaseContent" + name="relatedContent" + notnull="false" + cfc="contentbox.models.content.BaseContent" fieldtype="many-to-one" - fkcolumn ="FK_contentID" - lazy ="true" - index ="idx_contentCustomFields"; - - /* ********************************************************************* - ** PK + CONSTRAINTS - ********************************************************************* */ + fkcolumn="FK_contentID" + lazy="true" + index="idx_contentCustomFields"; + /********************************************************************** + * ** PK + CONSTRAINTS + **********************************************************************/ this.pk = "customFieldID"; this.memento = { - defaultIncludes : [ "key", "value" ], - defaultExcludes : [ "relatedContent" ], - neverInclude : [] + defaultIncludes: [ "key", "value"], + defaultExcludes: [ "relatedContent"], + neverInclude : [] }; this.constraints = { - "key" : { required : true, size : "1..255" }, - "value" : { required : true } + "key" : { required: true, size: "1..255" }, + "value": { required: true } }; - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ - function init(){ + function init() { super.init(); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/CustomFieldService.cfc b/modules/contentbox/models/content/CustomFieldService.cfc index 3ac1b55368..1aed018e60 100755 --- a/modules/contentbox/models/content/CustomFieldService.cfc +++ b/modules/contentbox/models/content/CustomFieldService.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -10,11 +10,11 @@ component extends="cborm.models.VirtualEntityService" singleton { /** * Constructor */ - CustomFieldService function init(){ + CustomFieldService function init() { // init it super.init( entityName = "cbCustomField" ); return this; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/Entry.cfc b/modules/contentbox/models/content/Entry.cfc index 27b450dd23..472261803d 100755 --- a/modules/contentbox/models/content/Entry.cfc +++ b/modules/contentbox/models/content/Entry.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -16,38 +16,37 @@ component joinColumn ="contentID" discriminatorValue="Entry" { - - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="excerpt" - column ="excerpt" + name="excerpt" + column="excerpt" notnull="false" ormtype="text" default="" - length ="8000"; + length="8000"; - /* ********************************************************************* - ** NON PERSISTED PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** NON PERSISTED PROPERTIES + **********************************************************************/ property name="renderedExcerpt" persistent="false"; - /* ********************************************************************* - ** CONSTRAINTS - ********************************************************************* */ + /********************************************************************** + * ** CONSTRAINTS + **********************************************************************/ - /* ********************************************************************* - ** CONSTRUCTOR - ********************************************************************* */ + /********************************************************************** + * ** CONSTRUCTOR + **********************************************************************/ /** * constructor */ - function init(){ - var props = [ "excerpt" ]; + function init() { + var props = [ "excerpt"]; appendToMemento( props, "defaultIncludes" ); appendToMemento( [], "defaultExcludes" ); appendToMementoProfile( props, "response" ); @@ -55,42 +54,47 @@ component super.init(); - variables.categories = []; - variables.customFields = []; + variables.categories = []; + variables.customFields = []; variables.renderedContent = ""; variables.renderedExcerpt = ""; - variables.createdDate = now(); - variables.contentType = "Entry"; + variables.createdDate = now(); + variables.contentType = "Entry"; return this; } - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ /** * has excerpt */ - boolean function hasExcerpt(){ + boolean function hasExcerpt() { return len( getExcerpt() ) GT 0; } /** * Render excerpt */ - any function renderExcerpt(){ + any function renderExcerpt() { // Check if we need to translate - if ( NOT len( variables.renderedExcerpt ) ) { - lock name="contentbox.excerptrendering.#getContentID()#" type="exclusive" throwontimeout="true" timeout="10" { - if ( NOT len( variables.renderedExcerpt ) ) { + if ( !len( variables.renderedExcerpt ) ) { + lock + name ="contentbox.excerptrendering.#getContentID()#" + type ="exclusive" + throwontimeout="true" + timeout ="10" + { + if ( !len( variables.renderedExcerpt ) ) { // render excerpt out, prepare builder var builder = createObject( "java", "java.lang.StringBuilder" ).init( getExcerpt() ); // announce renderings with data, so content renderers can process them variables.interceptorService.announce( - "cb_onContentRendering", - { builder : builder, content : this } - ); + "cb_onContentRendering", + { builder: builder, content: this } + ); // store processed content variables.renderedExcerpt = builder.toString(); } @@ -117,7 +121,7 @@ component required boolean publish, required any originalSlugRoot, required any newSlugRoot - ){ + ) { // Original cloning! if ( arguments.original.hasExcerpt() ) { setExcerpt( arguments.original.getExcerpt() ); @@ -126,4 +130,4 @@ component return super.clone( argumentCollection = arguments ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/EntryService.cfc b/modules/contentbox/models/content/EntryService.cfc index 449476eeb9..00d6711c60 100755 --- a/modules/contentbox/models/content/EntryService.cfc +++ b/modules/contentbox/models/content/EntryService.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -6,14 +6,13 @@ * Manages blog entry content */ component extends="ContentService" singleton { - // Inject generic content service property name="contentService" inject="id:ContentService@contentbox"; /** * Constructor */ - EntryService function init(){ + EntryService function init() { // init it super.init( entityName = "cbEntry", useQueryCaching = true ); @@ -28,9 +27,9 @@ component extends="ContentService" singleton { * * @return Saved entry */ - function save( required any entry, string originalSlug = "" ){ + function save( required any entry, string originalSlug = "" ) { // Only create relocations for slug changes to published entries - if ( entry.getIsPublished() && !isNull( arguments.originalSlug ) AND len( arguments.originalSlug ) ) { + if ( entry.getIsPublished() && !isNull( arguments.originalSlug ) && len( arguments.originalSlug ) ) { addRelocation( arguments.entry, arguments.originalSlug ); } return super.save( arguments.entry ); @@ -67,22 +66,21 @@ component extends="ContentService" singleton { boolean showInSearch = false, string siteId = "", string propertyList - ){ - var results = { "count" : 0, "entries" : [] }; + ) { + var results = { "count": 0, "entries": [] }; // criteria queries - var c = newCriteria(); + var c = newCriteria(); // stub out activeContent alias based on potential conditions... // this way, we don't have to worry about accidentally creating it twice, or not creating it at all if ( - ( arguments.author NEQ "all" ) || - ( len( arguments.search ) ) || - ( findNoCase( "modifiedDate", arguments.sortOrder ) ) + ( arguments.author NEQ "all" ) || ( len( arguments.search ) ) || + ( findNoCase( "modifiedDate", arguments.sortOrder ) ) ) { c.createAlias( - associationName: "contentVersions", - alias : "ac", - withClause : getRestrictions().isTrue( "ac.isActive" ) - ); + associationName = "contentVersions", + alias = "ac", + withClause = getRestrictions().isTrue( "ac.isActive" ) + ); } // only search shownInSearch bits if ( arguments.showInSearch ) { @@ -90,7 +88,10 @@ component extends="ContentService" singleton { } // isPublished filter if ( arguments.isPublished NEQ "any" ) { - c.isEq( "isPublished", javacast( "boolean", arguments.isPublished ) ); + c.isEq( + "isPublished", + javacast( "boolean", arguments.isPublished ) + ); } // Author Filter if ( arguments.author NEQ "all" ) { @@ -106,9 +107,9 @@ component extends="ContentService" singleton { if ( arguments.searchActiveContent ) { // like disjunctions c.$or( - c.restrictions.like( "title", "%#arguments.search#%" ), - c.restrictions.like( "ac.content", "%#arguments.search#%" ) - ); + c.restrictions.like( "title", "%#arguments.search#%" ), + c.restrictions.like( "ac.content", "%#arguments.search#%" ) + ); } else { c.like( "title", "%#arguments.search#%" ); } @@ -116,13 +117,12 @@ component extends="ContentService" singleton { // Category Filter if ( arguments.category NEQ "all" ) { // Uncategorized? - if ( arguments.category eq "none" ) { + if ( arguments.category EQ "none" ) { c.isEmpty( "categories" ); - } - // With categories - else { + } else { + // With categories // search the association - c.createAlias( "categories", "cats" ).isIn( "cats.categoryID", [ arguments.category ] ); + c.createAlias( "categories", "cats" ).isIn( "cats.categoryID", [ arguments.category] ); } } // Site Filter @@ -138,9 +138,8 @@ component extends="ContentService" singleton { "modifiedDate", "ac.createdDate" ); - } - // default to title sorting - else if ( !len( arguments.sortOrder ) ) { + } else if ( !len( arguments.sortOrder ) ) { + // default to title sorting sortOrder = "publishedDate DESC"; } @@ -153,11 +152,11 @@ component extends="ContentService" singleton { c.resultTransformer( c.DISTINCT_ROOT_ENTITY ); } results.entries = c.list( - offset = arguments.offset, - max = arguments.max, - sortOrder = arguments.sortOrder, - asQuery = false - ); + offset = arguments.offset, + max = arguments.max, + sortOrder = arguments.sortOrder, + asQuery = false + ); return results; } @@ -165,7 +164,7 @@ component extends="ContentService" singleton { /** * Get a query report of entries archive */ - function getArchiveReport(){ + function getArchiveReport() { // we use HQL so we can be DB independent using the map() hql function thanks to John Wish, you rock! var hql = "SELECT new map( count(*) as count, YEAR(publishedDate) as year, MONTH(publishedDate) as month ) FROM cbEntry @@ -175,7 +174,10 @@ component extends="ContentService" singleton { GROUP BY YEAR(publishedDate), MONTH(publishedDate) ORDER BY 2 DESC, 3 DESC"; // run report - return executeQuery( query = hql, params = { "isPublished" : true, "now" : now() } ); + return executeQuery( + query = hql, + params = { "isPublished": true, "now": now() } + ); } /** @@ -199,13 +201,13 @@ component extends="ContentService" singleton { numeric offset = 0, boolean asQuery = false, string siteId = "" - ){ + ) { var results = {}; - var hql = "FROM cbEntry + var hql = "FROM cbEntry WHERE isPublished = :isPublished AND passwordProtection = '' AND publishedDate <= :now"; - var params = { "isPublished" : true }; + var params = { "isPublished": true }; params[ "now" ] = now(); // Site @@ -260,8 +262,8 @@ component extends="ContentService" singleton { * * @site The site to get the export from */ - array function getAllForExport( required site ){ - return super.getAllForExport( findAllWhere( { site : arguments.site } ) ); + array function getAllForExport( required site ) { + return super.getAllForExport( findAllWhere( { site: arguments.site } ) ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/Page.cfc b/modules/contentbox/models/content/Page.cfc index fd2b1e6d3f..1835eb9937 100755 --- a/modules/contentbox/models/content/Page.cfc +++ b/modules/contentbox/models/content/Page.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -16,27 +16,26 @@ component joinColumn ="contentID" discriminatorValue="Page" { - - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ /** * The layout in a theme that will be used to render the page out */ property - name ="layout" - column ="layout" + name="layout" + column="layout" notnull="false" - length ="200" + length="200" default=""; /** * The ordering numeric sequence */ property - name ="order" - column ="order" + name="order" + column="order" notnull="false" ormtype="integer" default="0"; @@ -45,60 +44,59 @@ component * If true, this page is used when building automated menus. Else it is ignored. */ property - name ="showInMenu" - column ="showInMenu" + name="showInMenu" + column="showInMenu" notnull="true" ormtype="boolean" default="true" - index ="idx_showInMenu"; + index="idx_showInMenu"; /** * The excerpt for this page. This can be empty. */ property - name ="excerpt" - column ="excerpt" + name="excerpt" + column="excerpt" notnull="false" ormtype="text" default="" - length ="8000"; + length="8000"; - /* ********************************************************************* - ** NON PERSISTED PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** NON PERSISTED PROPERTIES + **********************************************************************/ property name="renderedExcerpt" persistent="false"; + /********************************************************************** + * ** CONSTRAINTS + **********************************************************************/ - /* ********************************************************************* - ** CONSTRAINTS - ********************************************************************* */ - - this.constraints[ "layout" ] = { required : false, size : "1..200" }; - this.constraints[ "order" ] = { required : true, type : "numeric" }; - this.constraints[ "showInMenu" ] = { required : false, type : "boolean" }; + this.constraints[ "layout" ] = { required: false, size: "1..200" }; + this.constraints[ "order" ] = { required: true, type: "numeric" }; + this.constraints[ "showInMenu" ] = { required: false, type: "boolean" }; - /* ********************************************************************* - ** CONSTRUCTOR - ********************************************************************* */ + /********************************************************************** + * ** CONSTRUCTOR + **********************************************************************/ - function init(){ - var props = [ "excerpt", "layout", "order", "showInMenu" ]; + function init() { + var props = [ "excerpt", "layout", "order", "showInMenu"]; appendToMemento( props, "defaultIncludes" ); appendToMementoProfile( props, "export" ); appendToMementoProfile( props, "response" ); super.init(); - variables.categories = []; - variables.customFields = []; + variables.categories = []; + variables.customFields = []; variables.renderedContent = ""; variables.renderedExcerpt = ""; - variables.allowComments = false; - variables.createdDate = now(); - variables.layout = "pages"; - variables.contentType = "Page"; - variables.order = 0; - variables.showInMenu = true; + variables.allowComments = false; + variables.createdDate = now(); + variables.layout = "pages"; + variables.contentType = "Page"; + variables.order = 0; + variables.showInMenu = true; // INHERITANCE LAYOUT STATIC variables.LAYOUT_INHERITANCE_KEY = "-inherit-"; @@ -106,29 +104,34 @@ component return this; } - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ /** * Verifies an excerpt exists in this content object via length checks */ - boolean function hasExcerpt(){ + boolean function hasExcerpt() { return len( getExcerpt() ) GT 0; } - any function renderExcerpt(){ + any function renderExcerpt() { // Check if we need to translate - if ( NOT len( variables.renderedExcerpt ) ) { - lock name="contentbox.excerptrendering.#getContentID()#" type="exclusive" throwontimeout="true" timeout="10" { - if ( NOT len( variables.renderedExcerpt ) ) { + if ( !len( variables.renderedExcerpt ) ) { + lock + name ="contentbox.excerptrendering.#getContentID()#" + type ="exclusive" + throwontimeout="true" + timeout ="10" + { + if ( !len( variables.renderedExcerpt ) ) { // render excerpt out, prepare builder var builder = createObject( "java", "java.lang.StringBuilder" ).init( getExcerpt() ); // announce renderings with data, so content renderers can process them variables.interceptorService.announce( - "cb_onContentRendering", - { builder : builder, content : this } - ); + "cb_onContentRendering", + { builder: builder, content: this } + ); // store processed content variables.renderedExcerpt = builder.toString(); } @@ -141,17 +144,17 @@ component /** * Get the layout or if empty the default convention of "pages" */ - function getLayoutWithDefault(){ + function getLayoutWithDefault() { return ( len( getLayout() ) ? getLayout() : "pages" ); } /** * Get layout with layout inheritance, if none found return normal saved layout */ - function getLayoutWithInheritance(){ + function getLayoutWithInheritance() { var thisLayout = getLayout(); // check for inheritance and parent? - if ( thisLayout eq variables.LAYOUT_INHERITANCE_KEY AND hasParent() ) { + if ( thisLayout EQ variables.LAYOUT_INHERITANCE_KEY && hasParent() ) { return getParent().getLayoutWithInheritance(); } // Else return the layout @@ -175,7 +178,7 @@ component required boolean publish, required any originalSlugRoot, required any newSlugRoot - ){ + ) { // Do page property cloning setLayout( arguments.original.getLayout() ); setShowInMenu( arguments.original.getShowInMenu() ); @@ -190,11 +193,11 @@ component /** * Verifies if the current page is the current site homepage */ - boolean function isHomepage(){ + boolean function isHomepage() { if ( !hasSite() ) { return false; } - return ( getSite().getHomePage() eq getSlug() ); + return ( getSite().getHomePage() EQ getSlug() ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/PageService.cfc b/modules/contentbox/models/content/PageService.cfc index a931a92246..a19ab80c75 100755 --- a/modules/contentbox/models/content/PageService.cfc +++ b/modules/contentbox/models/content/PageService.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -6,14 +6,13 @@ * Service layer for all Page operations */ component extends="ContentService" singleton { - // Inject generic content service property name="contentService" inject="id:ContentService@contentbox"; /** * Constructor */ - PageService function init(){ + PageService function init() { // init it super.init( entityName = "cbPage", useQueryCaching = true ); @@ -28,24 +27,24 @@ component extends="ContentService" singleton { * * @return Saved page */ - function save( required any page, string originalSlug = "" ){ + function save( required any page, string originalSlug = "" ) { transaction { // Save the target page super.save( arguments.page ); // Update all affected child pages if any on slug updates, much like nested set updates its nodes, we update our slugs - if ( !isNull( arguments.originalSlug ) AND len( arguments.originalSlug ) ) { + if ( !isNull( arguments.originalSlug ) && len( arguments.originalSlug ) ) { addRelocation( arguments.page, arguments.originalSlug ); var pagesInNeed = newCriteria().like( "slug", "#arguments.originalSlug#/%" ).list(); for ( var thisPage in pagesInNeed ) { addRelocation( thisPage, thisPage.getSlug() ); thisPage.setSlug( - replaceNoCase( - thisPage.getSlug(), - arguments.originalSlug, - arguments.page.getSlug() - ) - ); + replaceNoCase( + thisPage.getSlug(), + arguments.originalSlug, + arguments.page.getSlug() + ) + ); super.save( thisPage ); } } @@ -74,10 +73,10 @@ component extends="ContentService" singleton { * @return struct = { pages, count } */ struct function search( - string search = "", - string isPublished = "any", - string author = "all", - string creator = "all", + string search = "", + string isPublished = "any", + string author = "all", + string creator = "all", string parent, string category = "all", numeric max = 0, @@ -87,23 +86,22 @@ component extends="ContentService" singleton { boolean showInSearch = false, string siteID = "", string propertyList - ){ - var results = { "count" : 0, "pages" : [] }; + ) { + var results = { "count": 0, "pages": [] }; // criteria queries - var c = newCriteria(); + var c = newCriteria(); // stub out activeContent alias based on potential conditions... // this way, we don't have to worry about accidentally creating it twice, or not creating it at all if ( - ( arguments.author NEQ "all" ) || - ( len( arguments.search ) ) || - ( findNoCase( "modifiedDate", arguments.sortOrder ) ) + ( arguments.author NEQ "all" ) || ( len( arguments.search ) ) || + ( findNoCase( "modifiedDate", arguments.sortOrder ) ) ) { c.createAlias( - associationName: "contentVersions", - alias : "ac", - withClause : getRestrictions().isTrue( "ac.isActive" ) - ); + associationName = "contentVersions", + alias = "ac", + withClause = getRestrictions().isTrue( "ac.isActive" ) + ); } // only search shownInSearch bits @@ -113,7 +111,10 @@ component extends="ContentService" singleton { // isPublished filter if ( arguments.isPublished NEQ "any" ) { - c.isEq( "isPublished", javacast( "boolean", arguments.isPublished ) ); + c.isEq( + "isPublished", + javacast( "boolean", arguments.isPublished ) + ); } // Author Filter @@ -137,15 +138,15 @@ component extends="ContentService" singleton { if ( arguments.searchActiveContent ) { // like disjunctions c.$or( - c.restrictions.like( "title", "%#arguments.search#%" ), - c.restrictions.like( "slug", "%#arguments.search#%" ), - c.restrictions.like( "ac.content", "%#arguments.search#%" ) - ); + c.restrictions.like( "title", "%#arguments.search#%" ), + c.restrictions.like( "slug", "%#arguments.search#%" ), + c.restrictions.like( "ac.content", "%#arguments.search#%" ) + ); } else { c.$or( - c.restrictions.like( "title", "%#arguments.search#%" ), - c.restrictions.like( "slug", "%#arguments.search#%" ) - ); + c.restrictions.like( "title", "%#arguments.search#%" ), + c.restrictions.like( "slug", "%#arguments.search#%" ) + ); } } @@ -161,13 +162,12 @@ component extends="ContentService" singleton { // Category Filter if ( arguments.category NEQ "all" ) { // Uncategorized? - if ( arguments.category eq "none" ) { + if ( arguments.category EQ "none" ) { c.isEmpty( "categories" ); - } - // With categories - else { + } else { + // With categories // search the association - c.createAlias( "categories", "cats" ).isIn( "cats.categoryID", [ arguments.category ] ); + c.createAlias( "categories", "cats" ).isIn( "cats.categoryID", [ arguments.category] ); } } @@ -179,9 +179,8 @@ component extends="ContentService" singleton { "modifiedDate", "ac.createdDate" ); - } - // default to title sorting - else if ( !len( arguments.sortOrder ) ) { + } else if ( !len( arguments.sortOrder ) ) { + // default to title sorting sortOrder = "title asc"; } @@ -194,11 +193,11 @@ component extends="ContentService" singleton { c.resultTransformer( c.DISTINCT_ROOT_ENTITY ); } results.pages = c.list( - offset = arguments.offset, - max = arguments.max, - sortOrder = arguments.sortOrder, - asQuery = false - ); + offset = arguments.offset, + max = arguments.max, + sortOrder = arguments.sortOrder, + asQuery = false + ); return results; } @@ -223,25 +222,26 @@ component extends="ContentService" singleton { * @return struct of { count, content } */ function findPublishedContent( - numeric max = 0, - numeric offset = 0, - any searchTerm = "", - any category = "", - boolean asQuery = false, - string sortOrder = "publishedDate DESC", + numeric max = 0, + numeric offset = 0, + any searchTerm = "", + any category = "", + boolean asQuery = false, + string sortOrder = "publishedDate DESC", any parent, string slugPrefix = "", string siteID = "", string properties, - string authorID = "", + string authorID = "", boolean showInMenu, string slugSearch = "" - ){ - arguments.criteria = newCriteria() - // Show only pages with showInMenu criteria? - .when( !isNull( arguments.showInMenu ), function( c ){ - arguments.c.isEq( "showInMenu", javacast( "boolean", showInMenu ) ); - } ); + ) { + arguments.criteria = newCriteria().when( + !isNull( arguments.showInMenu ), + function( c ) { + arguments.c.isEq( "showInMenu", javacast( "boolean", showInMenu ) ); + } + ); // run criteria query and projections count return super.findPublishedContent( argumentCollection = arguments ); @@ -252,13 +252,11 @@ component extends="ContentService" singleton { * * @site The site to get the export from */ - array function getAllForExport( required site ){ - return super.getAllForExport( - newCriteria() - .isNull( "parent" ) - .isEq( "site", arguments.site ) - .list() - ); + array function getAllForExport( required site ) { + return super.getAllForExport( newCriteria() + .isNull( "parent" ) + .isEq( "site", arguments.site ) + .list() ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/Relocation.cfc b/modules/contentbox/models/content/Relocation.cfc index fac5725a79..d30df74017 100644 --- a/modules/contentbox/models/content/Relocation.cfc +++ b/modules/contentbox/models/content/Relocation.cfc @@ -14,61 +14,51 @@ component cachename ="cbRelocation" cacheuse ="read-write" { - - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="relocationID" - column ="relocationID" + name="relocationID" + column="relocationID" fieldtype="id" generator="uuid" - length ="36" - ormtype ="string" - update ="false"; + length="36" + ormtype="string" + update="false"; - property - name ="slug" - notnull="true" - length ="500" - default=""; + property name="slug" notnull="true" length="500" default=""; /** An optional manual target - may be used if no content is assigned **/ - property - name ="target" - notnull="false" - length ="500" - default=""; + property name="target" notnull="false" length="500" default=""; - /* ********************************************************************* - ** RELATIONSHIPS - ********************************************************************* */ + /********************************************************************** + * ** RELATIONSHIPS + **********************************************************************/ property - name ="site" - notnull ="true" - cfc ="contentbox.models.system.Site" + name="site" + notnull="true" + cfc="contentbox.models.system.Site" fieldtype="many-to-one" - fkcolumn ="FK_siteID" - fetch ="join"; + fkcolumn="FK_siteID" + fetch="join"; // O2O -> Content property - name ="relatedContent" - notnull ="false" - cfc ="contentbox.models.content.BaseContent" + name="relatedContent" + notnull="false" + cfc="contentbox.models.content.BaseContent" fieldtype="many-to-one" - fkcolumn ="FK_contentID" - lazy ="false" - fetch ="select"; - - /* ********************************************************************* - ** PK + CONSTRAINTS - ********************************************************************* */ + fkcolumn="FK_contentID" + lazy="false" + fetch="select"; + /********************************************************************** + * ** PK + CONSTRAINTS + **********************************************************************/ this.pk = "relocationID"; this.memento = { - defaultIncludes : [ + defaultIncludes: [ "relocationID", "createdDate", "modifiedDate", @@ -79,17 +69,17 @@ component }; this.constraints = { - "slug" : { - required : true, - size : "1..500", - validator : "UniqueSiteFieldValidator@contentbox" + "slug": { + required : true, + size : "1..500", + validator: "UniqueSiteFieldValidator@contentbox" } }; // overload method to clean any leading or trailing slashes - function setSlug( value ){ + function setSlug( value ) { variables.slug = arrayToList( listToArray( arguments.value, "/" ), "/" ); return this; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/RelocationService.cfc b/modules/contentbox/models/content/RelocationService.cfc index a238075901..87aca7a2b2 100644 --- a/modules/contentbox/models/content/RelocationService.cfc +++ b/modules/contentbox/models/content/RelocationService.cfc @@ -1,37 +1,37 @@ /** -******************************************************************************** -ContentBox - A Modular Content Platform -Copyright 2012 by Luis Majano and Ortus Solutions, Corp -www.ortussolutions.com -******************************************************************************** -Apache License, Version 2.0 - -Copyright Since [2012] [Luis Majano and Ortus Solutions,Corp] - -Licensed under the Apache License, Version 2.0 (the "License" ); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -******************************************************************************** -* A generic content service for content objects -*/ + * ******************************************************************************** + * ContentBox - A Modular Content Platform + * Copyright 2012 by Luis Majano and Ortus Solutions, Corp + * www.ortussolutions.com + * ******************************************************************************** + * Apache License, Version 2.0 + * + * Copyright Since [2012] [Luis Majano and Ortus Solutions,Corp] + * + * Licensed under the Apache License, Version 2.0 (the "License" ); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ******************************************************************************** + * A generic content service for content objects + */ component extends="cborm.models.VirtualEntityService" singleton { - // DI property name="log" inject="logbox:logger:{this}"; + property name="CBHelper" inject="CBHelper@contentbox"; /** * Constructor */ - function init(){ + function init() { super.init( entityname = "cbRelocation", queryCaching = true ); return this; } @@ -49,35 +49,46 @@ component extends="cborm.models.VirtualEntityService" singleton { * @return struct of { count, relocations } */ struct function search( - search = "", - siteID = "", + search = "", + siteID = "", boolean isPublic, max = 0, offset = 0, sortOrder = "slug asc" - ){ - var results = { "count" : 0, "relocations" : [] }; - var c = newCriteria() + ) { + var results = { "count": 0, "relocations": [] }; + var c = newCriteria() + .when( + len( arguments.search ), + function( c ) { + c.like( "slug", "%#search#%" ); + } + ) + .when( + len( arguments.siteID ), + function( c ) { + c.isEq( "site.siteID", siteID ); + } + ) // Search Criteria - .when( len( arguments.search ), function( c ){ - c.like( "slug", "%#search#%" ); - } ) + // Site Filter - .when( len( arguments.siteID ), function( c ){ - c.isEq( "site.siteID", siteID ); - } ) + // Content ID filter - .when( !isNull( arguments.contentID ), function( c ){ - c.isEq( "relatedContent.contentID", arguments.contentID ); - } ); + .when( + !isNull( arguments.contentID ), + function( c ) { + c.isEq( "relatedContent.contentID", arguments.contentID ); + } + ); // run criteria query and projections count - results.count = c.count( "relocationID" ); + results.count = c.count( "relocationID" ); results.relocations = c.list( - offset : arguments.offset, - max : arguments.max, - sortOrder: arguments.sortOrder - ); + offset = arguments.offset, + max = arguments.max, + sortOrder = arguments.sortOrder + ); return results; } @@ -88,19 +99,25 @@ component extends="cborm.models.VirtualEntityService" singleton { * @contentItem the content item to associate to this relocation * @originalSlug the slug which will be relocated */ - Relocation function createContentRelocation( required BaseContent contentItem, required string originalSlug ){ - var siteId = arguments.contentItem.getSite().getSiteID(); + Relocation function createContentRelocation( + required BaseContent contentItem, + required string originalSlug + ) { + var siteId = arguments + .contentItem + .getSite() + .getSiteID(); var relocation = newCriteria() .createAlias( "site", "site" ) .isEq( "site.siteID", siteId ) .isEq( "slug", arguments.originalSlug ) .get(); if ( isNull( relocation ) ) { - relocation = new ( + relocation = new( properties = { - "slug" : arguments.originalSlug, - "relatedContent" : arguments.contentItem, - "site" : siteId + "slug" : arguments.originalSlug, + "relatedContent": arguments.contentItem, + "site" : siteId } ); } else { @@ -116,18 +133,18 @@ component extends="cborm.models.VirtualEntityService" singleton { * @slug The URI to be checked * @target The target to relocate the URI to */ - Relocation function createTargetRelocation( required string slug, required string target ){ - var site = variables.cbHelper.site(); + Relocation function createTargetRelocation( required string slug, required string target ) { + var site = variables.cbHelper.site(); var relocation = newCriteria() .isEq( "site", site ) .isEq( "slug", arguments.originalSlug ) .get(); if ( isNull( relocation ) ) { - relocation = new ( + relocation = new( properties = { - "slug" : arguments.slug, - "target" : arguments.target, - "site" : site + "slug" : arguments.slug, + "target": arguments.target, + "site" : site } ); } else { @@ -148,7 +165,7 @@ component extends="cborm.models.VirtualEntityService" singleton { required string slug, string contentType = "Page", Site site - ){ + ) { param arguments.site = variables.CBHelper.site(); return newCriteria() @@ -159,4 +176,4 @@ component extends="cborm.models.VirtualEntityService" singleton { .get(); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/Stats.cfc b/modules/contentbox/models/content/Stats.cfc index e82f8b416d..271d7d3bc1 100644 --- a/modules/contentbox/models/content/Stats.cfc +++ b/modules/contentbox/models/content/Stats.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -14,51 +14,49 @@ component cachename ="cbStats" cacheuse ="read-write" { - - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="statsID" - column ="statsID" + name="statsID" + column="statsID" fieldtype="id" generator="uuid" - length ="36" - ormtype ="string" - update ="false"; + length="36" + ormtype="string" + update="false"; property - name ="hits" - column ="hits" + name="hits" + column="hits" notnull="false" ormtype="long" default="0"; - /* ********************************************************************* - ** RELATIONSHIPS - ********************************************************************* */ + /********************************************************************** + * ** RELATIONSHIPS + **********************************************************************/ // O2O -> Content property - name ="relatedContent" - notnull ="true" - cfc ="contentbox.models.content.BaseContent" + name="relatedContent" + notnull="true" + cfc="contentbox.models.content.BaseContent" fieldtype="one-to-one" - fkcolumn ="FK_contentID" - lazy ="true"; - - /* ********************************************************************* - ** PK + CONSTRAINTS - ********************************************************************* */ + fkcolumn="FK_contentID" + lazy="true"; + /********************************************************************** + * ** PK + CONSTRAINTS + **********************************************************************/ this.pk = "statsID"; - this.memento = { defaultIncludes : [ "hits" ], defaultExcludes : [ "" ] }; + this.memento = { defaultIncludes: [ "hits"], defaultExcludes: [ ""] }; - this.constraints = { "hits" : { required : false, type : "numeric" } }; + this.constraints = { "hits": { required: false, type: "numeric" } }; - function init(){ + function init() { super.init(); return this; } @@ -66,11 +64,11 @@ component /** * Build a snapshot of the related content */ - struct function getRelatedContentSnapshot(){ + struct function getRelatedContentSnapshot() { if ( hasRelatedContent() ) { return getRelatedContent().getInfoSnapshot(); } return {}; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/StatsService.cfc b/modules/contentbox/models/content/StatsService.cfc index 633d023813..46a3e9d458 100644 --- a/modules/contentbox/models/content/StatsService.cfc +++ b/modules/contentbox/models/content/StatsService.cfc @@ -1,51 +1,50 @@ /** -******************************************************************************** -ContentBox - A Modular Content Platform -Copyright 2012 by Luis Majano and Ortus Solutions, Corp -www.ortussolutions.com -******************************************************************************** -Apache License, Version 2.0 - -Copyright Since [2012] [Luis Majano and Ortus Solutions,Corp] - -Licensed under the Apache License, Version 2.0 (the "License" ); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -******************************************************************************** -* A generic content service for content objects -*/ + * ******************************************************************************** + * ContentBox - A Modular Content Platform + * Copyright 2012 by Luis Majano and Ortus Solutions, Corp + * www.ortussolutions.com + * ******************************************************************************** + * Apache License, Version 2.0 + * + * Copyright Since [2012] [Luis Majano and Ortus Solutions,Corp] + * + * Licensed under the Apache License, Version 2.0 (the "License" ); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ******************************************************************************** + * A generic content service for content objects + */ component extends="cborm.models.VirtualEntityService" singleton { - // DI property name="settingService" inject="settingService@contentbox"; + property name="log" inject="logbox:logger:{this}"; /** * Constructor */ - function init(){ + function init() { super.init( entityname = "cbStats", queryCaching = true ); return this; } - /** * Determine if we have a bot */ - function isUserAgentABot(){ + function isUserAgentABot() { var userAgent = lCase( CGI.http_user_agent ); var aBotRegex = listToArray( settingService.getSetting( "cb_content_bot_regex" ), chr( 13 ) ); // iterate and try to match for ( var thisBot in aBotRegex ) { - if ( arrayLen( reMatch( thisBot, userAgent ) ) gt 0 ) { + if ( arrayLen( reMatch( thisBot, userAgent ) ) GT 0 ) { return true; } } @@ -58,10 +57,10 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @contentId The site to filter on */ - numeric function getTotalHitsByContent( string contentId = "" ){ + numeric function getTotalHitsByContent( string contentId = "" ) { var oStat = newCriteria() .isEq( "relatedContent.contentID", arguments.contentId ) - .withProjections( property: "hits" ) + .withProjections( property = "hits" ) .get(); return ( isNull( oStat ) ? 0 : oStat ); } @@ -71,41 +70,41 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @content. The content object to update the hits on */ - StatsService function syncUpdateHits( required content ){ + StatsService function syncUpdateHits( required content ) { // are we tracking hit counts? if ( variables.settingService.getSetting( "cb_content_hit_count" ) ) { try { // try to match a bot? or ignored bots? - if ( variables.settingService.getSetting( "cb_content_hit_ignore_bots" ) OR !isUserAgentABot() ) { + if ( variables.settingService.getSetting( "cb_content_hit_ignore_bots" ) || !isUserAgentABot() ) { queryExecute( "UPDATE cb_stats SET hits = hits + 1, modifiedDate = :modifiedDate WHERE FK_contentID = :contentId", { - modifiedDate : { - value : createODBCDateTime( now() ), - cfsqltype : "timestamp" + modifiedDate: { + value : createODBCDateTime( now() ), + cfsqltype: "timestamp" }, - contentId : arguments.content.getContentId() + contentId: arguments.content.getContentId() }, - { result : "local.qResults" } + { result: "local.qResults" } ); // if no record, means, new record, so insert - if ( qResults.recordcount eq 0 ) { - save( this.new( { hits : 1, relatedContent : arguments.content } ) ); + if ( qResults.recordcount EQ 0 ) { + save( this.new( { hits: 1, relatedContent: arguments.content } ) ); } } - } catch ( any e ) { + } catch (any e) { log.error( - "Error hit tracking contentID: #arguments.content.getContentId()#. #e.message# #e.detail#", - e - ); + "Error hit tracking contentID: #arguments.content.getContentId()#. #e.message# #e.detail#", + e + ); } } return this; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/renderers/BaseRenderer.cfc b/modules/contentbox/models/content/renderers/BaseRenderer.cfc index 597e257481..89f3de6ae4 100644 --- a/modules/contentbox/models/content/renderers/BaseRenderer.cfc +++ b/modules/contentbox/models/content/renderers/BaseRenderer.cfc @@ -6,15 +6,16 @@ * Our base content renderer */ component accessors="true" { - // DI property name="cb" inject="id:CBHelper@contentbox"; + property name="log" inject="logbox:logger:{this}"; /** * Base Configure */ - void function configure(){ + void function configure() { + } /** @@ -30,18 +31,18 @@ component accessors="true" { required builder, required indexOf, required replaceWith - ){ + ) { var rLocation = arguments.builder.indexOf( arguments.indexOf ); - var rLen = len( arguments.indexOf ); + var rLen = len( arguments.indexOf ); // Loop findings of same instances to replace - while ( rLocation gt -1 ) { + while ( rLocation GT -1 ) { // Replace it arguments.builder.replace( - javacast( "int", rLocation ), - javacast( "int", rLocation + rLen ), - arguments.replaceWith - ); + javacast( "int", rLocation ), + javacast( "int", rLocation + rLen ), + arguments.replaceWith + ); // look again rLocation = arguments.builder.indexOf( arguments.indexOf, javacast( "int", rLocation ) ); } @@ -49,4 +50,4 @@ component accessors="true" { return arguments.builder; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/renderers/LinkRenderer.cfc b/modules/contentbox/models/content/renderers/LinkRenderer.cfc index 83a9e69ce7..e35c0620ea 100755 --- a/modules/contentbox/models/content/renderers/LinkRenderer.cfc +++ b/modules/contentbox/models/content/renderers/LinkRenderer.cfc @@ -5,12 +5,12 @@ * --- * A content renderer that transforms _page:XX_ and _entry:XX_ into page and entry links */ -component accessors="true" extends="BaseRenderer" { +component accessors="true" extends ="BaseRenderer" { /** * Execute on content translations for pages and blog entries */ - void function cb_onContentRendering( event, struct data ){ + void function cb_onContentRendering( event, struct data ) { translateContent( builder = arguments.data.builder, content = arguments.data.content, @@ -23,13 +23,17 @@ component accessors="true" extends="BaseRenderer" { * * @tagString The tag string */ - private function determineSlug( required tagString ){ + private function determineSlug( required tagString ) { var slug = reReplaceNoCase( arguments.tagString, "(page|entry|pagessl|entryssl)\:\[", "" ); - return reReplaceNoCase( slug, "\]$", "" ); + return reReplaceNoCase( + slug, + "\]$", + "" + ); } /** @@ -38,26 +42,45 @@ component accessors="true" extends="BaseRenderer" { * @builder java.lang.StringBuilder that contains all the content to manipulate * @content The content object that requested translation */ - private function translateContent( required builder, required content ){ + private function translateContent( required builder, required content ) { // our mustaches pattern - var regex = "(page|pagessl|entry|entryssl|root)\:\[[^\]]*]"; + var regex = "(page|pagessl|entry|entryssl|root)\:\[[^\]]*]"; // match contentbox links in our incoming builder and build our targets array and len - var targets = reMatchNoCase( regex, builder.toString() ); - var targetLen = arrayLen( targets ); - var tagString = ""; + var targets = reMatchNoCase( regex, builder.toString() ); + var targetLen = arrayLen( targets ); + var tagString = ""; var linkContent = ""; // Loop over found links - for ( var x = 1; x lte targetLen; x++ ) { + for ( var x = 1; x LTE targetLen; x++ ) { tagString = targets[ x ]; // convert quotes to standards - tagString = replace( tagString, "&##34;", """", "all" ); - tagString = replace( tagString, "&##39;", "'", "all" ); - tagString = replace( tagString, """, "'", "all" ); + tagString = replace( + tagString, + "&##34;", + """", + "all" + ); + tagString = replace( + tagString, + "&##39;", + "'", + "all" + ); + tagString = replace( + tagString, + """, + "'", + "all" + ); try { - var linkType = getToken( tagString, 1, ":" ); + var linkType = getToken( + tagString, + 1, + ":" + ); switch ( linkType ) { case "page": { linkContent = cb.linkPage( page = determineSlug( tagString ) ); @@ -80,7 +103,7 @@ component accessors="true" extends="BaseRenderer" { break; } } - } catch ( Any e ) { + } catch (Any e) { linkContent = "Error translating link: #e.message# #e.detail#"; log.error( "Error translating link on target: #targets[ x ]#", e ); } @@ -94,4 +117,4 @@ component accessors="true" extends="BaseRenderer" { } } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/renderers/MarkdownRenderer.cfc b/modules/contentbox/models/content/renderers/MarkdownRenderer.cfc index 6d4e462e1b..f414eaaf46 100644 --- a/modules/contentbox/models/content/renderers/MarkdownRenderer.cfc +++ b/modules/contentbox/models/content/renderers/MarkdownRenderer.cfc @@ -8,37 +8,53 @@ * @author Luis Majano */ component extends="coldbox.system.Interceptor" { - // DI property name="cb" inject="id:CBHelper@contentbox"; - property name="markdown" inject="Processor@cbmarkdown"; + property name="markdown" inject="Processor@cbmarkdown"; // MARKUP EDITOR variables.MARKDOWN_EDITOR = "Markdown"; /** * Execute on content translations for pages and blog entries */ - void function cb_onContentRendering( any event, struct data ){ + void function cb_onContentRendering( any event, struct data ) { // If no markup, then maybe a direct convent version conversion. if ( !structKeyExists( arguments.data.content, "getMarkup" ) ) { return; } - var thisMarkup = arguments.data.content.getMarkup(); + var thisMarkup = arguments + .data + .content + .getMarkup(); // Markdown - if ( !isNull( thisMarkup ) and thisMarkup eq variables.MARKDOWN_EDITOR ) { + if ( !isNull( thisMarkup ) && thisMarkup EQ variables.MARKDOWN_EDITOR ) { // convert markup to HTML - var results = variables.markdown.toHTML( arguments.data.builder.toString() ); + var results = variables.markdown.toHTML( arguments + .data + .builder + .toString() ); // Replace builder with new content - arguments.data.builder.replace( - javacast( "int", 0 ), - arguments.data.builder.length(), - results - ); + arguments + .data + .builder + .replace( + javacast( "int", 0 ), + arguments + .data + .builder + .length(), + results + ); } else if ( log.canDebug() ) { - log.debug( "Skipping Markdown translation as content markup is #arguments.data.content.getMarkup()#" ); + log.debug( + "Skipping Markdown translation as content markup is #arguments + .data + .content + .getMarkup()#" + ); } } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/renderers/SettingRenderer.cfc b/modules/contentbox/models/content/renderers/SettingRenderer.cfc index a23f1d0796..fd9ccddfdd 100755 --- a/modules/contentbox/models/content/renderers/SettingRenderer.cfc +++ b/modules/contentbox/models/content/renderers/SettingRenderer.cfc @@ -9,16 +9,16 @@ * * You can escape this notation by surrounding them with our tags */ -component accessors="true" extends="BaseRenderer" { - +component accessors="true" extends ="BaseRenderer" { // DI property name="settingService" inject="settingService@contentbox"; + property name="cbResourceService" inject="resourceService@cbi18n"; /** * Execute on content translations for pages and blog entries */ - void function cb_onContentRendering( required event, struct data = {} ){ + void function cb_onContentRendering( required event, struct data = {} ) { translateContent( builder = arguments.data.builder, content = arguments.data.content, @@ -37,7 +37,7 @@ component accessors="true" extends="BaseRenderer" { required builder, required content, required event - ){ + ) { // Escape values for non-rendering multiStringReplace( builder = arguments.builder, @@ -46,45 +46,47 @@ component accessors="true" extends="BaseRenderer" { ); // our mustaches pattern - var regex = "(?!\)\$\{([^\}])+\}(?!\<\/escape\>)"; + var regex = "(?!\)\$\{([^\}])+\}(?!\<\/escape\>)"; // match contentbox settings: ${setting} except surrounded by escape tags - var targets = reMatchNoCase( regex, builder.toString() ); - var targetLen = arrayLen( targets ); + var targets = reMatchNoCase( regex, builder.toString() ); + var targetLen = arrayLen( targets ); var thisSetting = ""; - var thisValue = ""; + var thisValue = ""; // Loop over found variables to build target + settings - for ( var x = 1; x lte targetLen; x++ ) { + for ( var x = 1; x LTE targetLen; x++ ) { try { // get the setting defined in ${} - thisSetting = mid( targets[ x ], 3, len( targets[ x ] ) - 3 ); + thisSetting = mid( + targets[ x ], + 3, + len( targets[ x ] ) - 3 + ); // Do we have rc or prc prefix? if ( reFindNoCase( "^p?rc\:", thisSetting ) ) { thisValue = event.getValue( - name = listLast( thisSetting, ":" ), - private = ( listFirst( thisSetting, ":" ) eq "rc" ? false : true ) - ); - } - // Do we have i18n? - else if ( reFindNoCase( "^i18n\:", thisSetting ) ) { + name = listLast( thisSetting, ":" ), + private = ( listFirst( thisSetting, ":" ) EQ "rc" ? false : true ) + ); + } else if ( reFindNoCase( "^i18n\:", thisSetting ) ) { + // Do we have i18n? var resource = listLast( thisSetting, ":" ); - var bundle = "default"; + var bundle = "default"; // check for resource@bundle convention: if ( find( "@", resource ) ) { - bundle = listLast( resource, "@" ); + bundle = listLast( resource, "@" ); resource = listFirst( resource, "@" ); } thisValue = variables.cbResourceService.getResource( resource = resource, bundle = bundle ); - } - // Normal Setting - else { + } else { + // Normal Setting thisValue = settingService.getSetting( - name = thisSetting, - defaultValue = "${Setting: #thisSetting# not found}" - ); + name = thisSetting, + defaultValue = "${Setting: #thisSetting# not found}" + ); } - } catch ( Any e ) { + } catch (Any e) { thisValue = "Error translating setting on target #thisSetting#: #e.message# #e.detail#"; log.error( "Error translating setting on target: #thisSetting#", e ); } @@ -98,4 +100,4 @@ component accessors="true" extends="BaseRenderer" { } } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/renderers/WidgetRenderer.cfc b/modules/contentbox/models/content/renderers/WidgetRenderer.cfc index 1c268ebb42..83e375212e 100755 --- a/modules/contentbox/models/content/renderers/WidgetRenderer.cfc +++ b/modules/contentbox/models/content/renderers/WidgetRenderer.cfc @@ -5,15 +5,14 @@ * --- * A content renderer that transforms {{{}}} into widget executions */ -component accessors="true" extends="BaseRenderer" { - +component accessors="true" extends ="BaseRenderer" { // DI property name="widgetService" inject="id:widgetService@contentbox"; /** * Execute on content translations for pages and blog entries */ - void function cb_onContentRendering( event, struct data ){ + void function cb_onContentRendering( event, struct data ) { translateContent( builder = arguments.data.builder, content = arguments.data.content, @@ -27,7 +26,7 @@ component accessors="true" extends="BaseRenderer" { * @builder java.lang.StringBuilder that contains all the content to manipulate * @content The content object that requested translation */ - private function translateContent( required builder, content ){ + private function translateContent( required builder, content ) { parseTagWidgets( argumentCollection = arguments ); parseTripleMustacheWidgets( argumentCollection = arguments ); } @@ -38,65 +37,88 @@ component accessors="true" extends="BaseRenderer" { * @builder java.lang.StringBuilder that contains all the content to manipulate * @content The content object that requested translation */ - private void function parseTagWidgets( required builder, required content ){ + private void function parseTagWidgets( required builder, required content ) { // widget tag syntax - var regex = "]*>(.*?)"; + var regex = "]*>(.*?)"; // match widgets in our incoming builder and build our targets array and len - var targets = reMatchNoCase( regex, builder.toString() ); + var targets = reMatchNoCase( regex, builder.toString() ); var targetLen = arrayLen( targets ); // Loop over found tags - for ( var x = 1; x lte targetLen; x++ ) { + for ( var x = 1; x LTE targetLen; x++ ) { var tagAttributes = xmlParse( targets[ x ] ).widget.XmlAttributes; try { - var widgetName = tagAttributes.widgetname; - var widgetType = tagAttributes.widgettype; - var widgetUDF = structKeyExists( tagAttributes, "widgetUDF" ) ? tagAttributes.widgetUDF : "renderIt"; + var widgetName = tagAttributes.widgetname; + var widgetType = tagAttributes.widgettype; + var widgetUDF = structKeyExists( tagAttributes, "widgetUDF" ) ? tagAttributes.widgetUDF : "renderIt"; var isModuleWidget = widgetType == "Module"; - var isThemeWidget = widgetType == "Theme"; + var isThemeWidget = widgetType == "Theme"; // Widget Executions - var oWidget = ""; + var oWidget = ""; var oWidgetMethod = ""; var widgetContent = ""; // Detect Widget and Method Calls if ( find( ".", widgetName ) ) { - oWidget = widgetService.getWidget( "#getToken( widgetName, 1, "." )#" ); - oWidgetMethod = getToken( widgetName, 2, "." ); + oWidget = widgetService.getWidget( + "#getToken( + widgetName, + 1, + "." + )#" + ); + oWidgetMethod = getToken( + widgetName, + 2, + "." + ); } else if ( isModuleWidget ) { // Render out the module widget - oWidget = widgetService.getWidget( name = widgetName, type = "module" ); + oWidget = widgetService.getWidget( name = widgetName, type = "module" ); oWidgetMethod = widgetUDF; } else if ( isThemeWidget ) { // Render out the theme widget - oWidget = widgetService.getWidget( name = widgetName, type = "theme" ); + oWidget = widgetService.getWidget( name = widgetName, type = "theme" ); oWidgetMethod = widgetUDF; } else { oWidget = widgetService.getWidget( - name = widgetName, - type = widgetService.discoverWidgetType( widgetName ) - ); + name = widgetName, + type = widgetService.discoverWidgetType( widgetName ) + ); oWidgetMethod = widgetUDF; } // lucee 4.5 split due to invoke bug - if ( server.keyExists( "lucee" ) and server.lucee.version.getToken( 1, "." ) == 4 ) { - widgetContent = evaluate( "oWidget.#oWidgetMethod#( argumentCollection=tagAttributes )" ); + if ( + server.keyExists( "lucee" ) && + server + .lucee + .version + .getToken( 1, "." ) == + 4 + ) { + widgetContent = evaluate( + "oWidget.#oWidgetMethod#( argumentCollection=tagAttributes )" + ); } else { // Render out the widgets - widgetContent = invoke( oWidget, oWidgetMethod, tagAttributes ); + widgetContent = invoke( + oWidget, + oWidgetMethod, + tagAttributes + ); } // Verify null widgetContent if ( isNull( widgetContent ) ) { log.warn( - "Widget: #widgetName# produce no content in page #arguments.content.getTitle()#", - tagAttributes - ); + "Widget: #widgetName# produce no content in page #arguments.content.getTitle()#", + tagAttributes + ); widgetContent = ""; } - } catch ( Any e ) { + } catch (Any e) { widgetContent = "Error translating tag widget: #e.message#"; if ( len( e.detail ) ) { @@ -107,7 +129,10 @@ component accessors="true" extends="BaseRenderer" { widgetContent &= "
StackTrace:
#e.stacktrace#
"; } - log.error( "Error translating tag widget on target: #targets[ x ]#", e ); + log.error( + "Error translating tag widget on target: #targets[ x ]#", + e + ); } // PROCESS REPLACING @@ -125,7 +150,7 @@ component accessors="true" extends="BaseRenderer" { * @builder java.lang.StringBuilder that contains all the content to manipulate * @content The content object that requested translation */ - private void function parseTripleMustacheWidgets( required builder, required content ){ + private void function parseTripleMustacheWidgets( required builder, required content ) { // Escape values for non-rendering multiStringReplace( builder = arguments.builder, @@ -134,56 +159,107 @@ component accessors="true" extends="BaseRenderer" { ); // our mustaches pattern - var regex = "(?!\<\/escape\>)\{\{\{[^\}]*\}\}\}(?!\<\/escape\>)"; + var regex = "(?!\<\/escape\>)\{\{\{[^\}]*\}\}\}(?!\<\/escape\>)"; // match widgets in our incoming builder and build our targets array and len - var targets = reMatch( regex, builder.toString() ); - var targetLen = arrayLen( targets ); + var targets = reMatch( regex, builder.toString() ); + var targetLen = arrayLen( targets ); var moduleName = ""; // Loop over found mustaches {{{Widget}}} - for ( var x = 1; x lte targetLen; x++ ) { + for ( var x = 1; x LTE targetLen; x++ ) { // convert mustache to tag - var tagString = replace( targets[ x ], "{{{", "<" ); - tagString = replace( tagString, "}}}", "/>" ); + var tagString = replace( + targets[ x ], + "{{{", + "<" + ); + tagString = replace( + tagString, + "}}}", + "/>" + ); // convert quotes to standards - tagString = replace( tagString, "&##34;", """", "all" ); - tagString = replace( tagString, "&##39;", "'", "all" ); - tagString = replace( tagString, """, "'", "all" ); + tagString = replace( + tagString, + "&##34;", + """", + "all" + ); + tagString = replace( + tagString, + "&##39;", + "'", + "all" + ); + tagString = replace( + tagString, + """, + "'", + "all" + ); try { // Parse : separator from method to first argument if ( reFindNoCase( "\<[^\>\=\:\s]+\:", tagString ) ) { - tagString = replace( tagString, ":", " " ); + tagString = replace( + tagString, + ":", + " " + ); } // Parse arguments separated by commas - tagString = replace( tagString, "',", "' ", "all" ); - tagString = replace( tagString, """,", """ ", "all" ); + tagString = replace( + tagString, + "',", + "' ", + "all" + ); + tagString = replace( + tagString, + """,", + """ ", + "all" + ); var isModuleWidget = findNoCase( "@", tagString ) ? true : false; - var isThemeWidget = findNoCase( "~", tagString ) ? true : false; + var isThemeWidget = findNoCase( "~", tagString ) ? true : false; if ( isModuleWidget ) { var startPos = find( "@", tagString ) + 1; // default end is last character of closing tag. - var endPos = find( "/>", tagString ); + var endPos = find( "/>", tagString ); var spacePos = find( " ", tagString ); // If we have arguments, then change this to first break position if ( spacePos > 0 ) { endPos = spacePos; } // Get module name now - moduleName = mid( tagString, startPos, endPos - startPos ); + moduleName = mid( + tagString, + startPos, + endPos - startPos + ); // clean the tag - tagString = replaceNoCase( tagString, "@#moduleName#", "", "one" ); + tagString = replaceNoCase( + tagString, + "@#moduleName#", + "", + "one" + ); } if ( isThemeWidget ) { - tagString = reReplace( tagString, "~", "", "one" ); + tagString = reReplace( + tagString, + "~", + "", + "one" + ); } // Parse it now as XML - var tagXML = xmlParse( tagString ); + var tagXML = xmlParse( tagString ); var widgetName = tagXML.XMLRoot.XMLName; var widgetArgs = {}; @@ -200,50 +276,74 @@ component accessors="true" extends="BaseRenderer" { } // Widget Executions - var oWidget = ""; + var oWidget = ""; var oWidgetMethod = ""; var widgetContent = ""; // Detect direct method call if ( find( ".", widgetName ) ) { oWidget = widgetService.getWidget( - name = "#getToken( widgetName, 1, "." )#", - type = widgetService.discoverWidgetType( widgetName ) + name = "#getToken( + widgetName, + 1, + "." + )#", + type = widgetService.discoverWidgetType( widgetName ) + ); + oWidgetMethod = getToken( + widgetName, + 2, + "." ); - oWidgetMethod = getToken( widgetName, 2, "." ); } else if ( isModuleWidget ) { - oWidget = widgetService.getWidget( name = widgetName & "@" & moduleName, type = "module" ); + oWidget = widgetService.getWidget( name = widgetName & "@" & moduleName, type = "module" ); oWidgetMethod = widgetArgs.widgetUDF; } else if ( isThemeWidget ) { - oWidget = widgetService.getWidget( name = widgetName, type = "theme" ); + oWidget = widgetService.getWidget( name = widgetName, type = "theme" ); oWidgetMethod = widgetArgs.widgetUDF; } else { oWidget = widgetService.getWidget( - name = widgetName, - type = widgetService.discoverWidgetType( widgetName ) - ); + name = widgetName, + type = widgetService.discoverWidgetType( widgetName ) + ); oWidgetMethod = widgetArgs.widgetUDF; } // lucee 4.5 split due to invoke bug - if ( server.keyExists( "lucee" ) and server.lucee.version.getToken( 1, "." ) == 4 ) { - widgetContent = evaluate( "oWidget.#oWidgetMethod#( argumentCollection=widgetArgs )" ); + if ( + server.keyExists( "lucee" ) && + server + .lucee + .version + .getToken( 1, "." ) == + 4 + ) { + widgetContent = evaluate( + "oWidget.#oWidgetMethod#( argumentCollection=widgetArgs )" + ); } else { // Render out the widgets - widgetContent = invoke( oWidget, oWidgetMethod, widgetArgs ); + widgetContent = invoke( + oWidget, + oWidgetMethod, + widgetArgs + ); } // Verify null widgetContent if ( isNull( widgetContent ) ) { log.warn( - "Widget: #widgetName# produce no content in page #arguments.content.getTitle()#", - tagAttributes - ); + "Widget: #widgetName# produce no content in page #arguments.content.getTitle()#", + tagAttributes + ); widgetContent = ""; } - } catch ( Any e ) { + } catch (Any e) { widgetContent = "Error translating markup widget: #e.message# #e.detail# #e.stacktrace#"; - log.error( "Error translating markup widget on target: #targets[ x ]#", e ); + log.error( + "Error translating markup widget on target: #targets[ x ]#", + e + ); } // PROCESS REPLACING @@ -255,4 +355,4 @@ component accessors="true" extends="BaseRenderer" { } } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/content/util/ContentCacheCleanup.cfc b/modules/contentbox/models/content/util/ContentCacheCleanup.cfc index 9129c5ec89..c17f38c2fd 100644 --- a/modules/contentbox/models/content/util/ContentCacheCleanup.cfc +++ b/modules/contentbox/models/content/util/ContentCacheCleanup.cfc @@ -1,11 +1,12 @@ -/** +/** * This interceptor monitors pages, posts and custom html content so it can purge caches on updates */ component extends="coldbox.system.Interceptor" { - // DI Injections property name="settingService" inject="settingService@contentbox"; + property name="commentService" inject="commentService@contentbox"; + property name="contentService" inject="contentService@contentbox"; /** @@ -14,8 +15,12 @@ component extends="coldbox.system.Interceptor" { * @event The request context * @data Intercept data */ - function cbui_onCommentPost( event, data ){ - doCacheCleanup( arguments.data.content.buildContentCacheCleanupKey(), arguments.data.content ); + function cbui_onCommentPost( event, data ) { + doCacheCleanup( arguments + .data + .content + .buildContentCacheCleanupKey(), + arguments.data.content ); } /** @@ -24,15 +29,19 @@ component extends="coldbox.system.Interceptor" { * @event The request context * @data Intercept data */ - function cbadmin_onCommentStatusUpdate( event, data ){ - variables.commentService + function cbadmin_onCommentStatusUpdate( event, data ) { + variables + .commentService .getAll( arguments.data.commentID ) - .each( function( thisComment ){ - doCacheCleanup( - arguments.thisComment.getRelatedContent().buildContentCacheCleanupKey(), - arguments.thisComment.getRelatedContent() - ); - } ); + .each( + function( thisComment ) { + doCacheCleanup( arguments + .thisComment + .getRelatedContent() + .buildContentCacheCleanupKey(), + arguments.thisComment.getRelatedContent() ); + } + ); } /** @@ -41,7 +50,7 @@ component extends="coldbox.system.Interceptor" { * @event The request context * @data Intercept data */ - function cbadmin_preCommentRemove( event, data ){ + function cbadmin_preCommentRemove( event, data ) { var oComment = variables.commentService.get( arguments.data.commentID ); doCacheCleanup( oComment.getRelatedContent().buildContentCacheCleanupKey(), oComment.getRelatedContent() ); } @@ -52,8 +61,12 @@ component extends="coldbox.system.Interceptor" { * @event The request context * @data Intercept data */ - function cbadmin_postEntrySave( event, data ){ - doCacheCleanup( arguments.data.content.buildContentCacheCleanupKey(), arguments.data.content ); + function cbadmin_postEntrySave( event, data ) { + doCacheCleanup( arguments + .data + .content + .buildContentCacheCleanupKey(), + arguments.data.content ); } /** @@ -62,8 +75,12 @@ component extends="coldbox.system.Interceptor" { * @event The request context * @data Intercept data */ - function cbadmin_preEntryRemove( event, data ){ - doCacheCleanup( arguments.data.content.buildContentCacheCleanupKey(), arguments.data.content ); + function cbadmin_preEntryRemove( event, data ) { + doCacheCleanup( arguments + .data + .content + .buildContentCacheCleanupKey(), + arguments.data.content ); } /** @@ -72,8 +89,12 @@ component extends="coldbox.system.Interceptor" { * @event The request context * @data Intercept data */ - function cbadmin_postPageSave( event, data ){ - doCacheCleanup( arguments.data.content.buildContentCacheCleanupKey(), arguments.data.content ); + function cbadmin_postPageSave( event, data ) { + doCacheCleanup( arguments + .data + .content + .buildContentCacheCleanupKey(), + arguments.data.content ); } /** @@ -82,8 +103,12 @@ component extends="coldbox.system.Interceptor" { * @event The request context * @data Intercept data */ - function cbadmin_prePageRemove( event, data ){ - doCacheCleanup( arguments.data.content.buildContentCacheCleanupKey(), arguments.data.content ); + function cbadmin_prePageRemove( event, data ) { + doCacheCleanup( arguments + .data + .content + .buildContentCacheCleanupKey(), + arguments.data.content ); } /** @@ -92,8 +117,12 @@ component extends="coldbox.system.Interceptor" { * @event The request context * @data Intercept data */ - function cbadmin_postContentStoreSave( event, data ){ - doCacheCleanup( arguments.data.content.buildContentCacheCleanupKey(), arguments.data.content ); + function cbadmin_postContentStoreSave( event, data ) { + doCacheCleanup( arguments + .data + .content + .buildContentCacheCleanupKey(), + arguments.data.content ); } /** @@ -102,12 +131,16 @@ component extends="coldbox.system.Interceptor" { * @event The request context * @data Intercept data */ - function cbadmin_preContentStoreRemove( event, data ){ - doCacheCleanup( arguments.data.content.buildContentCacheCleanupKey(), arguments.data.content ); + function cbadmin_preContentStoreRemove( event, data ) { + doCacheCleanup( arguments + .data + .content + .buildContentCacheCleanupKey(), + arguments.data.content ); } /*********************************************************************************************************/ - /* PRIVATE */ + /* PRIVATE */ /*********************************************************************************************************/ /** @@ -116,28 +149,32 @@ component extends="coldbox.system.Interceptor" { * @cacheKey The cache key to use * @content The content object */ - private function doCacheCleanup( required string cacheKey, any content ){ + private function doCacheCleanup( required string cacheKey, any content ) { // Log it variables.log.info( - "=> Starting content cache cleanup for : #arguments.content.getContentType()#:#arguments.cacheKey#..." - ); + "=> Starting content cache cleanup for : #arguments.content.getContentType()#:#arguments.cacheKey#..." + ); // Get settings var settings = variables.settingService.getAllSettings(); // Get appropriate cache provider - var cache = variables.cacheBox.getCache( settings.cb_content_cacheName ); + var cache = variables.cacheBox.getCache( settings.cb_content_cacheName ); // clear content translation caches cache.clearByKeySnippet( keySnippet = arguments.cacheKey, async = true ); // log it - variables.log.info( "+ Cleared content translation caches for: #arguments.cacheKey#" ); + variables.log.info( + "+ Cleared content translation caches for: #arguments.cacheKey#" + ); // clear content wrapper caches - var blogPrefix = ( arguments.content.getContentType() eq "Entry" ? "#settings.cb_site_blog_entrypoint#/" : "" ); + var blogPrefix = ( arguments.content.getContentType() EQ "Entry" ? "#settings.cb_site_blog_entrypoint#/" : "" ); var wrapperKey = "#blogPrefix##arguments.content.getSlug()#"; variables.contentService.clearPageWrapperCaches( slug = wrapperKey, async = true ); // log it - variables.log.info( "+ Cleared content wrapper caches using wrapper key of: #wrapperKey#" ); + variables.log.info( + "+ Cleared content wrapper caches using wrapper key of: #wrapperKey#" + ); // Clear category count caches variables.contentService.clearAllCategoryCountCaches(); @@ -150,8 +187,8 @@ component extends="coldbox.system.Interceptor" { variables.log.info( "+ Cleared all sitemap caches" ); variables.log.info( - "=> Finalized cache content cleanup for #arguments.content.getContentType()#:#arguments.cacheKey#" - ); + "=> Finalized cache content cleanup for #arguments.content.getContentType()#:#arguments.cacheKey#" + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/exporters/BaseExporter.cfc b/modules/contentbox/models/exporters/BaseExporter.cfc index 5bd7bcde0a..4650c574c0 100644 --- a/modules/contentbox/models/exporters/BaseExporter.cfc +++ b/modules/contentbox/models/exporters/BaseExporter.cfc @@ -5,8 +5,7 @@ * --- * Base exporter class */ -component accessors=true { - +component accessors="#true#" { // DI property name="log" inject="logbox:logger:{this}"; @@ -40,16 +39,15 @@ component accessors=true { */ property name="allowedFormats"; - /** * Constructor */ - function init(){ + function init() { setFileName( createUUID() ); setFormat( "json" ); setPriority( 1 ); - variables.name = ""; + variables.name = ""; variables.allowedFormats = ""; return this; @@ -58,8 +56,8 @@ component accessors=true { /** * Determines if exporter is valid based on validation criteria */ - boolean function isValid(){ + boolean function isValid() { return !arrayLen( validate() ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/exporters/ContentBoxExporter.cfc b/modules/contentbox/models/exporters/ContentBoxExporter.cfc index 7877adcc6a..319d1f2d67 100644 --- a/modules/contentbox/models/exporters/ContentBoxExporter.cfc +++ b/modules/contentbox/models/exporters/ContentBoxExporter.cfc @@ -5,8 +5,7 @@ * --- * Export ContentBox data based on user selection. This is a transient object */ -component accessors=true { - +component accessors="#true#" { /** * The exporters to use */ @@ -29,35 +28,55 @@ component accessors=true { // DI property name="moduleSettings" inject="coldbox:setting:modules"; + property name="entryService" inject="id:entryService@contentbox"; + property name="pageService" inject="id:pageService@contentbox"; + property name="categoryService" inject="id:categoryService@contentbox"; + property name="contentStoreService" inject="id:contentStoreService@contentbox"; + property name="menuService" inject="id:menuService@contentbox"; + property name="securityRuleService" inject="id:securityRuleService@contentbox"; + property name="authorService" inject="id:authorService@contentbox"; + property name="roleService" inject="id:roleService@contentbox"; + property name="permissionService" inject="id:permissionService@contentbox"; + property name="settingService" inject="id:settingService@contentbox"; + property name="securityService" inject="id:securityService@contentbox"; + property name="moduleService" inject="id:moduleService@contentbox"; + property name="themeService" inject="id:themeService@contentbox"; + property name="widgetService" inject="id:widgetService@contentbox"; + property name="siteService" inject="id:siteService@contentbox"; + property name="templateService" inject="id:emailtemplateService@contentbox"; + property name="log" inject="logbox:logger:{this}"; + property name="zipUtil" inject="zipUtil@contentbox"; + property name="wirebox" inject="wirebox"; + property name="HTMLHelper" inject="HTMLHelper@coldbox"; /** * Constructor */ - ContentBoxExporter function init(){ - variables.exporters = []; - variables.descriptor = {}; + ContentBoxExporter function init() { + variables.exporters = []; + variables.descriptor = {}; variables.dataServiceMappings = {}; - variables.filePathMappings = {}; + variables.filePathMappings = {}; return this; } @@ -65,126 +84,126 @@ component accessors=true { /** * On DI Complete */ - function onDIComplete(){ + function onDIComplete() { var contentBoxPath = variables.moduleSettings[ "contentbox" ].path; - var customPath = variables.moduleSettings[ "contentbox-custom" ].path; + var customPath = variables.moduleSettings[ "contentbox-custom" ].path; variables.dataServiceMappings = { - "authors" : { - fileName : "authors", - service : "authorService", - displayName : "Authors", - priority : 3 + "authors": { + fileName : "authors", + service : "authorService", + displayName: "Authors", + priority : 3 }, - "categories" : { - fileName : "categories", - service : "categoryService", - displayName : "Categories", - priority : 1 + "categories": { + fileName : "categories", + service : "categoryService", + displayName: "Categories", + priority : 1 }, - "contentstore" : { - fileName : "contentstore", - service : "contentStoreService", - displayName : "Content Store", - priority : 4 + "contentstore": { + fileName : "contentstore", + service : "contentStoreService", + displayName: "Content Store", + priority : 4 }, - "entries" : { - fileName : "entries", - service : "entryService", - displayName : "Entries", - priority : 4 + "entries": { + fileName : "entries", + service : "entryService", + displayName: "Entries", + priority : 4 }, - "menus" : { - fileName : "menus", - service : "menuService", - displayName : "Menus", - priority : 5 + "menus": { + fileName : "menus", + service : "menuService", + displayName: "Menus", + priority : 5 }, - "pages" : { - fileName : "pages", - service : "pageService", - displayName : "Pages", - priority : 4 + "pages": { + fileName : "pages", + service : "pageService", + displayName: "Pages", + priority : 4 }, - "permissions" : { - fileName : "permissions", - service : "permissionService", - displayName : "Permissions", - priority : 1 + "permissions": { + fileName : "permissions", + service : "permissionService", + displayName: "Permissions", + priority : 1 }, - "permissionGroups" : { - fileName : "permissionGroups", - service : "permissionGroupService", - displayName : "Permission Groups", - priority : 2 + "permissionGroups": { + fileName : "permissionGroups", + service : "permissionGroupService", + displayName: "Permission Groups", + priority : 2 }, - "roles" : { - fileName : "roles", - service : "roleService", - displayName : "Roles", - priority : 2 + "roles": { + fileName : "roles", + service : "roleService", + displayName: "Roles", + priority : 2 }, - "securityrules" : { - fileName : "securityrules", - service : "securityRuleService", - displayName : "Security Rules", - priority : 1 + "securityrules": { + fileName : "securityrules", + service : "securityRuleService", + displayName: "Security Rules", + priority : 1 }, - "settings" : { - fileName : "settings", - service : "settingService", - displayName : "Settings", - priority : 1 + "settings": { + fileName : "settings", + service : "settingService", + displayName: "Settings", + priority : 1 }, - "sites" : { - fileName : "site", - service : "siteService", - displayName : "Site", - priority : 1 + "sites": { + fileName : "site", + service : "siteService", + displayName: "Site", + priority : 1 } }; variables.filePathMappings = { - "emailtemplates" : { - fileName : "emailtemplates", - displayName : "Email Templates", - directory : contentBoxPath & "/email_templates", - type : "template", - extension : "", - priority : 1 + "emailtemplates": { + fileName : "emailtemplates", + displayName: "Email Templates", + directory : contentBoxPath & "/email_templates", + type : "template", + extension : "", + priority : 1 }, - "medialibrary" : { - fileName : "medialibrary", - displayName : "Media Library", - directory : expandPath( variables.settingService.getSetting( "cb_media_directoryRoot" ) ), - includeFiles : "*", - type : "folder", - extension : "", - priority : 1 - }, - "modules" : { - fileName : "modules", - displayName : "Modules", - directory : customPath & "/_modules", + "medialibrary": { + fileName : "medialibrary", + displayName : "Media Library", + directory : expandPath( variables.settingService.getSetting( "cb_media_directoryRoot" ) ), + includeFiles: "*", type : "folder", extension : "", priority : 1 }, - "themes" : { - fileName : "themes", - displayName : "Themes", - directory : customPath & "/_themes", - type : "folder", - extension : "", - priority : 1 + "modules": { + fileName : "modules", + displayName: "Modules", + directory : customPath & "/_modules", + type : "folder", + extension : "", + priority : 1 }, - "widgets" : { - fileName : "widgets", - displayName : "Widgets", - directory : customPath & "/_widgets", - type : "component", - extension : ".cfc", - priority : 1 + "themes": { + fileName : "themes", + displayName: "Themes", + directory : customPath & "/_themes", + type : "folder", + extension : "", + priority : 1 + }, + "widgets": { + fileName : "widgets", + displayName: "Widgets", + directory : customPath & "/_widgets", + type : "component", + extension : ".cfc", + priority : 1 } }; } @@ -194,7 +213,7 @@ component accessors=true { * * @targets The struct of targets to prepare for export */ - ContentBoxExporter function setup( required struct targets ){ + ContentBoxExporter function setup( required struct targets ) { // loop over targets and build up exporters for ( var key in arguments.targets ) { // find config data struct for the given key @@ -213,15 +232,15 @@ component accessors=true { exporter.setFileName( config.def.fileName ); exporter.setDisplayName( config.def.displayName ); exporter.setContent( - variables[ config.def.service ].getAllForExport( variables.siteService.getCurrentWorkingSite() ) - ); + variables[ config.def.service ].getAllForExport( variables.siteService.getCurrentWorkingSite() ) + ); exporter.setPriority( config.def.priority ); break; - // add file exporter + // add file exporter case "file": - var includedFiles = !isBoolean( arguments.targets[ key ] ) && listLen( arguments.targets[ key ] ) ? arguments.targets[ - key - ] : "*"; + var includedFiles = !isBoolean( arguments.targets[ key ] ) && listLen( arguments.targets[ key ] ) + ? arguments.targets[ key ] + : "*"; var exporter = wirebox.getInstance( "fileExporter@contentbox" ); exporter.setFileName( config.def.fileName ); exporter.setDisplayName( config.def.displayName ); @@ -231,7 +250,6 @@ component accessors=true { // set included files dynamically from arguments exporter.setIncludeFiles( includedFiles ); break; - // add exporter } addExporter( exporter ); @@ -247,7 +265,7 @@ component accessors=true { * * @return SiteExporterService */ - ContentBoxExporter function addExporter( required any exporter ){ + ContentBoxExporter function addExporter( required any exporter ) { arrayAppend( variables.exporters, arguments.exporter ); return this; } @@ -255,7 +273,7 @@ component accessors=true { /** * Gets the descriptor def for the export, it builds it first. */ - struct function getDescriptor(){ + struct function getDescriptor() { // build descriptor return buildDescriptor(); } @@ -263,10 +281,9 @@ component accessors=true { /** * Processes export! */ - struct function export(){ - var exportLog = createObject( "java", "java.lang.StringBuilder" ).init( - "Starting ContentBox package export...
" - ); + struct function export() { + var exportLog = createObject( "java", + "java.lang.StringBuilder" ).init( "Starting ContentBox package export...
" ); // do some directory checking/creating var tmpDirectory = getTempDirectory() & "cbexport"; if ( directoryExists( tmpDirectory ) ) { @@ -286,17 +303,21 @@ component accessors=true { var fileName = tmpDirectory & "/" & exporter.getFileName() & "." & exporter.getFormat(); // if all files, just grab directory if ( exporter.getIncludeFiles() == "*" ) { - exportLog.append( "Beginning export of all #exporter.getDisplayName()#
" ); + exportLog.append( + "Beginning export of all #exporter.getDisplayName()#
" + ); zipUtil.addFiles( - zipFilePath = fileName, - directory = exporter.getDirectory(), - recurse = true - ); - exportLog.append( "Export of all #exporter.getDisplayName()# complete!
" ); + zipFilePath = fileName, + directory = exporter.getDirectory(), + recurse = true + ); + exportLog.append( + "Export of all #exporter.getDisplayName()# complete!
" + ); } else { exportLog.append( - "Beginning export of #exporter.getDisplayName()#: #exporter.getFileList()#
" - ); + "Beginning export of #exporter.getDisplayName()#: #exporter.getFileList()#
" + ); if ( exporter.getType() == "folder" ) { var folders = listToArray( exporter.getFileList() ); var tmppath = tmpDirectory & "/tmp_" & exporter.getFileName(); @@ -313,18 +334,18 @@ component accessors=true { } // now add tmp to zip file zipUtil.addFiles( - zipFilePath = fileName, - directory = tmppath, - recurse = true - ); + zipFilePath = fileName, + directory = tmppath, + recurse = true + ); // finally, we can delete that now directoryDelete( tmppath, true ); } else { zipUtil.addFiles( - zipFilePath = fileName, - files = exporter.getFileList(), - recurse = true - ); + zipFilePath = fileName, + files = exporter.getFileList(), + recurse = true + ); } exportLog.append( "Export of #exporter.getDisplayName()# complete!
" ); } @@ -332,7 +353,10 @@ component accessors=true { } exportLog.append( "Creating package descriptor file
" ); // add descriptor file - fileWrite( tmpDirectory & "/descriptor.json", serializeJSON( getDescriptor() ) ); + fileWrite( + tmpDirectory & "/descriptor.json", + serializeJSON( getDescriptor() ) + ); exportLog.append( "Package descriptor complete!
" ); // done! now we just need to compress the whole thing @@ -340,16 +364,16 @@ component accessors=true { var exportFile = tmpDirectory & "/cbsite.cbox"; zipUtil.addFiles( - zipFilePath = exportFile, - directory = tmpDirectory, - recurse = true - ); + zipFilePath = exportFile, + directory = tmpDirectory, + recurse = true + ); exportLog.append( "ContentBox package export complete!
" ); var flattendExportLog = exportLog.toString(); log.info( flattendExportLog ); - return { "exportfile" : exportFile, exportlog : flattendExportLog }; + return { "exportfile": exportFile, exportlog: flattendExportLog }; } /** @@ -359,19 +383,19 @@ component accessors=true { * * @return Struct of { type : "data|file", def : data service mapping } */ - private struct function findConfig( required string key ){ + private struct function findConfig( required string key ) { var isData = structKeyExists( variables.dataServiceMappings, arguments.key ); var isFile = structKeyExists( variables.filePathMappings, arguments.key ); if ( isData ) { return { - "type" : "data", - "def" : variables.dataServiceMappings[ arguments.key ] + "type": "data", + "def" : variables.dataServiceMappings[ arguments.key ] }; } if ( isFile ) { return { - "type" : "file", - "def" : variables.filePathMappings[ arguments.key ] + "type": "file", + "def" : variables.filePathMappings[ arguments.key ] }; } return {}; @@ -380,30 +404,32 @@ component accessors=true { /** * Creates descriptor structure */ - private struct function buildDescriptor(){ + private struct function buildDescriptor() { var loggedInUser = variables.securityService.getAuthorSession(); - var descriptor = {}; + var descriptor = {}; // set static descriptor values descriptor[ "exportDate" ] = now(); descriptor[ "exportedBy" ] = "#loggedInUser.getFullName()# (#loggedInUser.getUsername()#)"; - descriptor[ "content" ] = {}; - descriptor[ "site" ] = variables.siteService.getCurrentWorkingSite().getMemento(); + descriptor[ "content" ] = {}; + descriptor[ "site" ] = variables + .siteService + .getCurrentWorkingSite() + .getMemento(); // add dynamic content for ( var exporter in variables.exporters ) { descriptor[ "content" ][ exporter.getFileName() ] = { - "total" : exporter.getTotal(), - "name" : exporter.getDisplayName(), - "format" : exporter.getFormat(), - "filename" : exporter.getFileName() & "." & exporter.getFormat(), - "priority" : exporter.getPriority() + "total" : exporter.getTotal(), + "name" : exporter.getDisplayName(), + "format" : exporter.getFormat(), + "filename": exporter.getFileName() & "." & exporter.getFormat(), + "priority": exporter.getPriority() }; } setDescriptor( descriptor ); - return descriptor; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/exporters/DataExporter.cfc b/modules/contentbox/models/exporters/DataExporter.cfc index 3333059811..3904b4949e 100644 --- a/modules/contentbox/models/exporters/DataExporter.cfc +++ b/modules/contentbox/models/exporters/DataExporter.cfc @@ -5,12 +5,7 @@ * --- * Exporter for Data-based content */ -component - extends ="BaseExporter" - implements="contentbox.models.exporters.ICBExporter" - accessors =true -{ - +component extends ="BaseExporter" implements="contentbox.models.exporters.ICBExporter" accessors ="#true#" { /** * The records this exporter will export */ @@ -19,10 +14,10 @@ component /** * Constructor */ - DataExporter function init(){ + DataExporter function init() { super.init(); - variables.format = "json"; - variables.name = "DataExporter"; + variables.format = "json"; + variables.name = "DataExporter"; variables.allowedFormats = "json,xml"; return this; } @@ -30,7 +25,7 @@ component /** * Gets "total" based on content type */ - numeric function getTotal(){ + numeric function getTotal() { var total = 0; if ( !isNull( variables.content ) ) { if ( isArray( variables.content ) ) { @@ -49,7 +44,7 @@ component /** * Custom validator for this exporter...any rules can be applied */ - array function validate(){ + array function validate() { var errors = []; if ( isNull( getContent() ) || isSimpleValue( getContent() ) ) { arrayAppend( errors, "The data exporter does not contain any content!" ); @@ -61,9 +56,12 @@ component ); } if ( isNull( getFileName() ) || !len( getFileName() ) ) { - arrayAppend( errors, "A valid file name for the export must be specified!" ); + arrayAppend( + errors, + "A valid file name for the export must be specified!" + ); } return errors; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/exporters/FileExporter.cfc b/modules/contentbox/models/exporters/FileExporter.cfc index db3207ae92..7de7f6055e 100644 --- a/modules/contentbox/models/exporters/FileExporter.cfc +++ b/modules/contentbox/models/exporters/FileExporter.cfc @@ -5,21 +5,19 @@ * --- * Exporter for file-based content */ -component - extends ="BaseExporter" - implements="contentbox.models.exporters.ICBExporter" - accessors =true -{ - +component extends ="BaseExporter" implements="contentbox.models.exporters.ICBExporter" accessors ="#true#" { property name="directory" type="string"; + property name="includeFiles" type="string"; + property name="type" type="string"; + property name="extension" type="string"; /** * Constructor */ - public FileExporter function init(){ + public FileExporter function init() { super.init(); setFormat( "zip" ); @@ -27,7 +25,7 @@ component setType( "component" ); setExtension( "" ); - variables.name = "FileExporter"; + variables.name = "FileExporter"; variables.allowedFormats = "zip"; return this; @@ -36,10 +34,16 @@ component /** * Gets "total" based on content type */ - public numeric function getTotal(){ + public numeric function getTotal() { var total = 0; if ( getIncludeFiles() == "*" ) { - total = arrayLen( directoryList( getDirectory(), true, "name" ) ); + total = arrayLen( + directoryList( + getDirectory(), + true, + "name" + ) + ); } else { total = listLen( getIncludeFiles() ); } @@ -49,10 +53,13 @@ component /** * Custom validator for this exporter...any rules can be applied */ - public array function validate(){ + public array function validate() { var errors = []; if ( isNull( getDirectory() ) ) { - arrayAppend( errors, "The files exporter does not have a configured directory!" ); + arrayAppend( + errors, + "The files exporter does not have a configured directory!" + ); } if ( !listFindNoCase( variables.allowedFormats, getFormat() ) ) { arrayAppend( @@ -61,7 +68,10 @@ component ); } if ( isNull( getFileName() ) || !len( getFileName() ) ) { - arrayAppend( errors, "A valid file name for the export must be specified!" ); + arrayAppend( + errors, + "A valid file name for the export must be specified!" + ); } return errors; } @@ -69,15 +79,19 @@ component /** * Gets list of files (absolute paths) when not "all" options are chosen for export */ - public string function getFileList(){ - var files = ""; + public string function getFileList() { + var files = ""; var delimiter = type == "folder" ? "," : chr( 124 ); for ( var i = 1; i <= listLen( getIncludeFiles() ); i++ ) { var includeFile = listGetAt( getIncludeFiles(), i ); - var fileName = getDirectory() & "/" & includeFile & getExtension(); - files = listAppend( files, fileName, delimiter ); + var fileName = getDirectory() & "/" & includeFile & getExtension(); + files = listAppend( + files, + fileName, + delimiter + ); } return files; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/exporters/ICBExporter.cfc b/modules/contentbox/models/exporters/ICBExporter.cfc index 379b342e16..a3154e14af 100644 --- a/modules/contentbox/models/exporters/ICBExporter.cfc +++ b/modules/contentbox/models/exporters/ICBExporter.cfc @@ -21,5 +21,4 @@ interface { * Gets "total" based on content type */ public numeric function getTotal(); - -} +} \ No newline at end of file diff --git a/modules/contentbox/models/exporters/StaticExporter.cfc b/modules/contentbox/models/exporters/StaticExporter.cfc index c3addfc606..e6ccb7adc5 100644 --- a/modules/contentbox/models/exporters/StaticExporter.cfc +++ b/modules/contentbox/models/exporters/StaticExporter.cfc @@ -5,24 +5,32 @@ * --- * Static content exporter service */ -component accessors=true threadSafe singleton { - +component accessors="#true#" threadSafe singleton { // DI property name="settingService" inject="SettingService@contentbox"; + property name="pageService" inject="PageService@contentbox"; + property name="siteService" inject="siteService@contentbox"; + property name="entryService" inject="entryService@contentbox"; + property name="themeService" inject="ThemeService@contentbox"; + property name="categoryService" inject="CategoryService@contentbox"; + property name="uiConfig" inject="coldbox:moduleconfig:contentbox-ui"; + property name="interceptorService" inject="coldbox:interceptorService"; + property name="zipUtil" inject="zipUtil@contentbox"; + property name="Renderer" inject="Provider:Renderer@coldbox"; /** * Constructor */ - function init(){ + function init() { return this; } @@ -47,14 +55,14 @@ component accessors=true threadSafe singleton { required rc, required prc, required site - ){ - var lb = chr( 13 ) & chr( 10 ); + ) { + var lb = chr( 13 ) & chr( 10 ); var results = { - "exportLog" : createObject( "java", "java.lang.StringBuilder" ).init( - "Starting static site generation with the following options: #arguments.toString()#. #lb#" - ), - "exportDirectory" : arguments.exportDirectory, - "exportFile" : getTempDirectory() & "/" & createUUID() & ".zip" + "exportLog": createObject( "java", "java.lang.StringBuilder" ).init( + "Starting static site generation with the following options: #arguments.toString()#. #lb#" + ), + "exportDirectory": arguments.exportDirectory, + "exportFile" : getTempDirectory() & "/" & createUUID() & ".zip" }; var allSettings = variables.settingService.getAllSettings(); @@ -64,31 +72,37 @@ component accessors=true threadSafe singleton { } directoryCreate( arguments.exportDirectory ); - results.exportLog.append( "Created export directory: #arguments.exportDirectory# #lb#" ); + results.exportLog.append( + "Created export directory: #arguments.exportDirectory# #lb#" + ); // ************ Prepare as if we are doing a UI request ****************** // store UI module root - arguments.prc.cbRoot = getContextRoot() & arguments.event.getModuleRoot( "contentbox" ); + arguments.prc.cbRoot = getContextRoot() & arguments.event.getModuleRoot( "contentbox" ); // store module entry point - arguments.prc.cbEntryPoint = variables.uiConfig.entryPoint; + arguments.prc.cbEntryPoint = variables.uiConfig.entryPoint; // Place global cb options on scope - arguments.prc.cbSettings = allSettings; + arguments.prc.cbSettings = allSettings; // Place the site to export - arguments.prc.oCurrentSite = arguments.site; + arguments.prc.oCurrentSite = arguments.site; // Place the default theme - arguments.prc.cbTheme = arguments.prc.oCurrentSite.getActiveTheme(); + arguments.prc.cbTheme = arguments + .prc + .oCurrentSite + .getActiveTheme(); // Place the default theme record - arguments.prc.cbThemeRecord = variables.themeService.getThemeRecord( arguments.prc.cbTheme ); + arguments.prc.cbThemeRecord = variables.themeService.getThemeRecord( arguments.prc.cbTheme ); // Place theme root location - arguments.prc.cbthemeRoot = arguments.prc.cbRoot & "/themes/" & arguments.prc.cbTheme; + arguments.prc.cbthemeRoot = arguments.prc.cbRoot & "/themes/" & arguments.prc.cbTheme; // Place widgets root location - arguments.prc.cbWidgetRoot = arguments.prc.cbRoot & "/widgets"; + arguments.prc.cbWidgetRoot = arguments.prc.cbRoot & "/widgets"; // Marker to tell layouts we are in static export mode - arguments.prc.staticExport = true; + arguments.prc.staticExport = true; // Current Site - arguments.prc.cbSiteSettings = variables.settingService.getAllSiteSettings( - arguments.prc.oCurrentSite.getSlug() - ); + arguments.prc.cbSiteSettings = variables.settingService.getAllSiteSettings( arguments + .prc + .oCurrentSite + .getSlug() ); /******************************************************************************/ @@ -100,7 +114,10 @@ component accessors=true threadSafe singleton { ); // Copy over the theme directoryCopy( - arguments.prc.cbThemeRecord.path, + arguments + .prc + .cbThemeRecord + .path, arguments.exportDirectory & "/__theme", true ); @@ -112,20 +129,21 @@ component accessors=true threadSafe singleton { } // Announce export - interceptorService.announce( "cbadmin_preStaticSiteExport", { options : arguments } ); + interceptorService.announce( "cbadmin_preStaticSiteExport", { options: arguments } ); // Get root pages, we need objects in order to render out the site var aPages = variables.pageService.search( - parent = "", - siteID : arguments.site.getSiteID(), - sortOrder= "order asc" - ); + parent = "", + siteID = arguments.site.getSiteID(), + sortOrder = "order asc" + ); // Process Homepage - var oHomePage = variables.pageService.findBySlug( - slug : arguments.prc.oCurrentSite.getHomepage(), - siteID: arguments.site.getSiteID() - ); + var oHomePage = variables.pageService.findBySlug( slug = arguments + .prc + .oCurrentSite + .getHomepage(), + siteID = arguments.site.getSiteID() ); if ( !isNull( oHomePage ) && oHomepage.isLoaded() ) { // put in scope for fake access prc.page = oHomePage; @@ -159,13 +177,14 @@ component accessors=true threadSafe singleton { // Process blog entries if ( arguments.includeBlog ) { - var aEntries = variables.entryService.search( siteID: arguments.site.getSiteID() ); + var aEntries = variables.entryService.search( siteID = arguments.site.getSiteID() ); // Put all categories in prc for processing - prc.categories = variables.categoryService.search( isPublic: true, siteId: arguments.site.getSiteId() ).categories; + prc.categories = variables.categoryService.search( isPublic = true, + siteId = arguments.site.getSiteId() ).categories; // Process all entries for ( var thisEntry in aEntries.entries ) { // put in scope for fake access - prc.entry = thisEntry; + prc.entry = thisEntry; prc.comments = prc.entry.getComments(); // process it processStaticEntry( @@ -181,13 +200,16 @@ component accessors=true threadSafe singleton { // zip archive zipUtil.addFiles( - zipFilePath = results.exportFile, - directory = arguments.exportDirectory, - recurse = true - ); + zipFilePath = results.exportFile, + directory = arguments.exportDirectory, + recurse = true + ); // Announce export - interceptorService.announce( "cbadmin_postStaticSiteExport", { options : arguments, results : results } ); + interceptorService.announce( + "cbadmin_postStaticSiteExport", + { options: arguments, results: results } + ); // Remove creation Folder now directoryDelete( arguments.exportDirectory, true ); @@ -195,7 +217,7 @@ component accessors=true threadSafe singleton { return results; } - /*************************************** PRIVATE *************************************** */ + /*************************************** PRIVATE ****************************************/ /** * Process a static entry export @@ -214,8 +236,8 @@ component accessors=true threadSafe singleton { required prc, required exportDir, required settings - ){ - var allSettings = arguments.settings; + ) { + var allSettings = arguments.settings; var outputContent = ""; // announce event @@ -223,21 +245,35 @@ component accessors=true threadSafe singleton { // Render out entry arguments.event.setView( - view = "#arguments.prc.cbTheme#/views/entry", - module = arguments.prc.cbThemeRecord.module - ); + view = "#arguments.prc.cbTheme#/views/entry", + module = arguments + .prc + .cbThemeRecord + .module + ); outputContent = renderer.layout( - layout = "#arguments.prc.cbTheme#/layouts/blog", - module = arguments.prc.cbThemeRecord.module - ); + layout = "#arguments.prc.cbTheme#/layouts/blog", + module = arguments + .prc + .cbThemeRecord + .module + ); // ****** Content Conversions ****** // replace base tags - outputContent = reReplaceNoCase( outputContent, "]+?>", "", "all" ); + outputContent = reReplaceNoCase( + outputContent, + "]+?>", + "", + "all" + ); // replace local server addresses outputContent = replaceNoCase( outputContent, - arguments.content.getSite().getSiteRoot(), + arguments + .content + .getSite() + .getSiteRoot(), "/", "all" ); @@ -256,7 +292,7 @@ component accessors=true threadSafe singleton { } // Write it out fileWrite( arguments.exportDir & "/" & arguments.content.getSlug() & "/index.html", outputContent ); - }; + } /** * Process a static page export @@ -277,35 +313,49 @@ component accessors=true threadSafe singleton { required prc, required exportDir, required settings - ){ - var allSettings = arguments.settings; - var thisLayout = arguments.content.getLayoutWithInheritance(); + ) { + var allSettings = arguments.settings; + var thisLayout = arguments.content.getLayoutWithInheritance(); var outputContent = ""; // announce event interceptorService.announce( "cbui_preRequest" ); // Verify No Layout - if ( thisLayout eq "-no-layout-" ) { + if ( thisLayout EQ "-no-layout-" ) { outputContent = arguments.content.renderContent(); } else { arguments.event.setView( - view = "#arguments.prc.cbTheme#/views/page", - module = arguments.prc.cbThemeRecord.module - ); + view = "#arguments.prc.cbTheme#/views/page", + module = arguments + .prc + .cbThemeRecord + .module + ); outputContent = renderer.layout( - layout = "#arguments.prc.cbTheme#/layouts/#thisLayout#", - module = arguments.prc.cbThemeRecord.module - ); + layout = "#arguments.prc.cbTheme#/layouts/#thisLayout#", + module = arguments + .prc + .cbThemeRecord + .module + ); } // ****** Content Conversions ****** // replace base tags - outputContent = reReplaceNoCase( outputContent, "]+?>", "", "all" ); + outputContent = reReplaceNoCase( + outputContent, + "]+?>", + "", + "all" + ); // replace local server addresses outputContent = replaceNoCase( outputContent, - arguments.content.getSite().getSiteRoot(), + arguments + .content + .getSite() + .getSiteRoot(), "/", "all" ); @@ -346,6 +396,6 @@ component accessors=true threadSafe singleton { ); } } - }; + } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/importers/BlogCFCImporter.cfc b/modules/contentbox/models/importers/BlogCFCImporter.cfc index 89491aa3ae..da7c746e92 100644 --- a/modules/contentbox/models/importers/BlogCFCImporter.cfc +++ b/modules/contentbox/models/importers/BlogCFCImporter.cfc @@ -1,46 +1,56 @@ /** -******************************************************************************** -ContentBox - A Modular Content Platform -Copyright 2012 by Luis Majano and Ortus Solutions, Corp -www.ortussolutions.com -******************************************************************************** -Apache License, Version 2.0 - -Copyright Since [2012] [Luis Majano and Ortus Solutions,Corp] - -Licensed under the Apache License, Version 2.0 (the "License" ); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -******************************************************************************** -* Import a blogcfc database into contentbox -*/ + * ******************************************************************************** + * ContentBox - A Modular Content Platform + * Copyright 2012 by Luis Majano and Ortus Solutions, Corp + * www.ortussolutions.com + * ******************************************************************************** + * Apache License, Version 2.0 + * + * Copyright Since [2012] [Luis Majano and Ortus Solutions,Corp] + * + * Licensed under the Apache License, Version 2.0 (the "License" ); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ******************************************************************************** + * Import a blogcfc database into contentbox + */ component implements="contentbox.models.importers.ICBImporter" { - property name="categoryService" inject="id:categoryService@contentbox"; + property name="entryService" inject="id:entryService@contentbox"; + property name="pageService" inject="id:pageService@contentbox"; + property name="statsService" inject="id:statsService@contentbox"; + property name="authorService" inject="id:authorService@contentbox"; + property name="roleService" inject="id:roleService@contentbox"; + property name="commentService" inject="id:commentService@contentbox"; + property name="customFieldService" inject="id:customFieldService@contentbox"; + property name="log" inject="logbox:logger:{this}"; + property name="interceptorService" inject="coldbox:interceptorService"; + property name="settingService" inject="id:settingService@contentbox"; + property name="bCrypt" inject="BCrypt@BCrypt"; // ------------------------------------------------------------------------------------------------ // Constructor // ------------------------------------------------------------------------------------------------ - blogcfcImporter function init(){ + blogcfcImporter function init() { return this; } @@ -53,12 +63,12 @@ component implements="contentbox.models.importers.ICBImporter" { dsnPassword = "", defaultPassword = "", required roleID, - tableprefix = "" - ){ - var authorMap = {}; - var catMap = {}; - var entryMap = {}; - var slugMap = {}; + tableprefix = "" + ) { + var authorMap = {}; + var catMap = {}; + var entryMap = {}; + var slugMap = {}; var defaultAuthor = {}; log.info( "Starting import process: #arguments.toString()#" ); @@ -71,10 +81,10 @@ component implements="contentbox.models.importers.ICBImporter" { password = arguments.dsnPassword, sql = "select categoryid, categoryname, categoryalias, blog FROM tblBlogCategories" ).execute().getResult(); - for ( var x = 1; x lte qCategories.recordcount; x++ ) { + for ( var x = 1; x LTE qCategories.recordcount; x++ ) { var props = { - category : qCategories.categoryName[ x ], - slug : qCategories.categoryAlias[ x ] + category: qCategories.categoryName[ x ], + slug : qCategories.categoryAlias[ x ] }; var cat = categoryService.new( properties = props ); entitySave( cat ); @@ -94,14 +104,14 @@ component implements="contentbox.models.importers.ICBImporter" { password = arguments.dsnPassword, sql = "select username, password, name from tblUsers" ).execute().getResult(); - for ( var x = 1; x lte qAuthors.recordcount; x++ ) { + for ( var x = 1; x LTE qAuthors.recordcount; x++ ) { var props = { - email : qAuthors.username[ x ], - username : qAuthors.username[ x ], - password : bcrypt.hashPassword( defaultPassword ), - isActive : 1, - firstName : listFirst( qAuthors.name[ x ], " " ), - lastName : trim( + email : qAuthors.username[ x ], + username : qAuthors.username[ x ], + password : bcrypt.hashPassword( defaultPassword ), + isActive : 1, + firstName: listFirst( qAuthors.name[ x ], " " ), + lastName : trim( replaceNoCase( qAuthors.name[ x ], listFirst( qAuthors.name[ x ], " " ), @@ -110,7 +120,7 @@ component implements="contentbox.models.importers.ICBImporter" { ) }; - var author = authorService.findWhere( { username : qAuthors.username[ x ] } ); + var author = authorService.findWhere( { username: qAuthors.username[ x ] } ); if ( isNull( author ) ) { author = authorService.new( properties = props ); } @@ -137,31 +147,31 @@ component implements="contentbox.models.importers.ICBImporter" { sql = "select id, blog, title, alias, body from tblblogpages" ).execute().getResult(); - for ( var x = 1; x lte qPages.recordcount; x++ ) { + for ( var x = 1; x LTE qPages.recordcount; x++ ) { var props = { - title : qPages.title[ x ], - slug : qPages.alias[ x ], - content : qPages.body[ x ], - publishedDate : now(), - createdDate : now(), - isPublished : true, - allowComments : false, - layout : "pages" + title : qPages.title[ x ], + slug : qPages.alias[ x ], + content : qPages.body[ x ], + publishedDate: now(), + createdDate : now(), + isPublished : true, + allowComments: false, + layout : "pages" }; var page = pageService.new( properties = props ); // blogCFC has no concept of authored pages, so we grab the first author we find from blogCFC // This may need revising later. page.addNewContentVersion( - content = props.content, - changelog = "Imported content", - author = defaultAuthor - ); + content = props.content, + changelog = "Imported content", + author = defaultAuthor + ); page.setCreator( defaultAuthor ); entitySave( page ); } log.info( "Pages imported" ); - } catch ( any e ) { + } catch (any e) { log.info( "Error Importing Pages - Version might support Pages" ); } @@ -177,8 +187,8 @@ component implements="contentbox.models.importers.ICBImporter" { from tblBlogEntries " ).execute().getResult(); - for ( var x = 1; x lte q.recordcount; x++ ) { - var published = true; + for ( var x = 1; x LTE q.recordcount; x++ ) { + var published = true; var commentStatus = true; if ( !trim( q.released[ x ] ) ) { published = false; @@ -188,32 +198,31 @@ component implements="contentbox.models.importers.ICBImporter" { } var importedBody = q.Body[ x ] & q.moreBody[ x ]; - interceptorService.announce( "preImportEntry", { post : importedBody } ); + interceptorService.announce( "preImportEntry", { post: importedBody } ); importedBody = findImages( importedBody ); importedBody = convertContent( importedBody ); - interceptorService.announce( "postImportEntry", { post : importedBody } ); + interceptorService.announce( "postImportEntry", { post: importedBody } ); var props = { - title : q.title[ x ], - slug : q.alias[ x ], - content : importedBody, - excerpt : q.Body[ x ], - publishedDate : q.posted[ x ], - createdDate : q.posted[ x ], - isPublished : published, - allowComments : commentStatus, - hits : q.views[ x ] + title : q.title[ x ], + slug : q.alias[ x ], + content : importedBody, + excerpt : q.Body[ x ], + publishedDate: q.posted[ x ], + createdDate : q.posted[ x ], + isPublished : published, + allowComments: commentStatus, + hits : q.views[ x ] }; var entry = entryService.new( properties = props ); - var oStat = statsService.new( { hits : props.hits } ); + var oStat = statsService.new( { hits: props.hits } ); oStat.setRelatedContent( entry ); - entry.setStats( oStat ); entry.addNewContentVersion( - content = props.content, - changelog = "Imported content", - author = authorService.get( authorMap[ q.username[ x ] ] ) - ); + content = props.content, + changelog = "Imported content", + author = authorService.get( authorMap[ q.username[ x ] ] ) + ); entry.setCreator( authorService.get( authorMap[ q.username[ x ] ] ) ); // entry categories @@ -231,11 +240,15 @@ component implements="contentbox.models.importers.ICBImporter" { sql = thisSQL ).execute().getResult(); var aCategories = []; - for ( var y = 1; y lte qCategories.recordcount; y++ ) { - arrayAppend( aCategories, categoryService.get( catMap[ qCategories.categoryId[ y ] ] ) ); + for ( var y = 1; y LTE qCategories.recordcount; y++ ) { + arrayAppend( + aCategories, + categoryService.get( catMap[ qCategories.categoryId[ y ] ] ) + ); } entry.setCategories( aCategories ); entitySave( entry ); + statsService.save( oStat ); // Categories won't save in ContentBox Express without this flush :/ ormFlush(); @@ -249,15 +262,15 @@ component implements="contentbox.models.importers.ICBImporter" { sql = "select * from tblBlogComments where entryidfk = '#q.id[ x ]#'" ).execute().getResult(); - for ( var y = 1; y lte qComments.recordcount; y++ ) { + for ( var y = 1; y LTE qComments.recordcount; y++ ) { var props = { - content : qComments.comment[ y ], - author : qComments.name[ y ], - authorEmail : qComments.email[ y ], - createdDate : qComments.posted[ y ], - authorIP : "127.0.0.1", - isApproved : qComments.moderated[ y ], - authorUrl : qComments.website[ y ] + content : qComments.comment[ y ], + author : qComments.name[ y ], + authorEmail: qComments.email[ y ], + createdDate: qComments.posted[ y ], + authorIP : "127.0.0.1", + isApproved : qComments.moderated[ y ], + authorUrl : qComments.website[ y ] }; var comment = commentService.new( properties = props ); @@ -269,30 +282,28 @@ component implements="contentbox.models.importers.ICBImporter" { log.info( "Entry imported: #entry.getTitle()#" ); } log.info( "Entries imported successfully!" ); - } catch ( any e ) { - transaction action="rollback" { - } + } catch (any e) { + transaction action="rollback"; log.error( "Error importing blog: #e.message# #e.detail#", e ); rethrow; } - transaction action="commit" { - } + transaction action="commit"; } // ------------------------------------------------------------------------------------------------ // Convert blogCFC code blocks to a more uniform approach // ------------------------------------------------------------------------------------------------ - private string function convertContent( required string content ){ - if ( findNoCase( "", arguments.content ) and findNoCase( "", arguments.content ) ) { + private string function convertContent( required string content ) { + if ( findNoCase( "", arguments.content ) && findNoCase( "", arguments.content ) ) { var counter = findNoCase( "", arguments.content ); - while ( counter gte 1 ) { + while ( counter GTE 1 ) { var codeblock = reFindNoCase( "(?s)(.*)()(.*)()(.*)", arguments.content, 1, 1 ); - if ( arrayLen( codeblock.len ) gte 6 ) { + if ( arrayLen( codeblock.len ) GTE 6 ) { var codeportion = mid( arguments.content, codeblock.pos[ 4 ], @@ -300,15 +311,23 @@ component implements="contentbox.models.importers.ICBImporter" { ); if ( len( trim( codeportion ) ) ) { var result = "[code]#codeportion#[/code]"; - result = htmlCodeFormat( result ); + result = htmlCodeFormat( result ); } - var newbody = mid( arguments.content, 1, codeblock.len[ 2 ] ) & result & mid( + var newbody = mid( + arguments.content, + 1, + codeblock.len[ 2 ] + ) & result & mid( arguments.content, codeblock.pos[ 6 ], codeblock.len[ 6 ] ); arguments.content = newBody; - counter = findNoCase( "", arguments.content, counter ); + counter = findNoCase( + "", + arguments.content, + counter + ); } else { counter = 0; } @@ -320,13 +339,13 @@ component implements="contentbox.models.importers.ICBImporter" { // ------------------------------------------------------------------------------------------------ // find all images in a given entry and save them to the media manager // ------------------------------------------------------------------------------------------------ - private string function findImages( required string content ){ - var images = reMatchNoCase( "(?i)src=""[^>]*[^>](.*)(gif|jpg|png)""\1", arguments.content ); - var images1 = reMatchNoCase( "(?i)href=""[^>]*[^>](.*)(gif|jpg|png)""\1", arguments.content ); - var pattern = createObject( "java", "java.util.regex.Pattern" ); - var exp = "(?<=\=\"" )([^""])+(?=\"" )"; + private string function findImages( required string content ) { + var images = reMatchNoCase( "(?i)src=""[^>]*[^>](.*)(gif|jpg|png)""\1", arguments.content ); + var images1 = reMatchNoCase( "(?i)href=""[^>]*[^>](.*)(gif|jpg|png)""\1", arguments.content ); + var pattern = createObject( "java", "java.util.regex.Pattern" ); + var exp = "(?<=\=\"" )([^""])+(?=\"" )"; var mediaPath = expandPath( settingService.getSetting( "cb_media_directoryRoot" ) ); - var newUrl = "/__media/blogImages/"; + var newUrl = "/__media/blogImages/"; // Create a directory in the Media Manager for all the blog entry images if ( !directoryExists( mediaPath & "\blogImages" ) ) { @@ -339,7 +358,7 @@ component implements="contentbox.models.importers.ICBImporter" { for ( var item in images ) { var matcher = pattern.compile( exp ).matcher( item ); while ( matcher.find() ) { - var urlObj = matcher.group(); + var urlObj = matcher.group(); var fileName = listLast( matcher.group(), "/" ); var httpService = new http(); @@ -349,7 +368,11 @@ component implements="contentbox.models.importers.ICBImporter" { httpService.setGetAsBinary( "yes" ); var result = httpService.send().getPrefix(); fileWrite( mediaPath & "\blogImages\" & fileName, result.fileContent ); - arguments.content = replaceNoCase( arguments.content, urlObj, newUrl & fileName ); + arguments.content = replaceNoCase( + arguments.content, + urlObj, + newUrl & fileName + ); } } } @@ -359,7 +382,7 @@ component implements="contentbox.models.importers.ICBImporter" { for ( var item in images1 ) { var matcher = pattern.compile( exp ).matcher( item ); while ( matcher.find() ) { - var urlObj = matcher.group(); + var urlObj = matcher.group(); var fileName = listLast( matcher.group(), "/" ); var httpService = new http(); @@ -369,7 +392,11 @@ component implements="contentbox.models.importers.ICBImporter" { httpService.setGetAsBinary( "yes" ); var result = httpService.send().getPrefix(); fileWrite( mediaPath & "\blogImages\" & fileName, result.fileContent ); - arguments.content = replaceNoCase( arguments.content, urlObj, newUrl & fileName ); + arguments.content = replaceNoCase( + arguments.content, + urlObj, + newUrl & fileName + ); } } } @@ -377,4 +404,4 @@ component implements="contentbox.models.importers.ICBImporter" { return arguments.content; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/importers/ContentBoxImporter.cfc b/modules/contentbox/models/importers/ContentBoxImporter.cfc index ea23c130fc..ed8241ec7a 100644 --- a/modules/contentbox/models/importers/ContentBoxImporter.cfc +++ b/modules/contentbox/models/importers/ContentBoxImporter.cfc @@ -5,20 +5,22 @@ * --- * Import a .cbox package into ContentBOx */ -component accessors=true { - +component accessors="#true#" { /** * The import file names found */ property name="fileNames" type="array"; + /** * The location of the import file (zip|box) */ property name="ContentBoxPackagePath" type="any"; + /** * The location of the data services used for exporting */ property name="dataServiceMappings" type="struct"; + /** * The location of the file mappings used for exporting */ @@ -26,32 +28,49 @@ component accessors=true { // DI property name="moduleSettings" inject="coldbox:setting:modules"; + property name="entryService" inject="id:entryService@contentbox"; + property name="pageService" inject="id:pageService@contentbox"; + property name="categoryService" inject="id:categoryService@contentbox"; + property name="contentStoreService" inject="id:contentStoreService@contentbox"; + property name="menuService" inject="id:menuService@contentbox"; + property name="securityRuleService" inject="id:securityRuleService@contentbox"; + property name="authorService" inject="id:authorService@contentbox"; + property name="roleService" inject="id:roleService@contentbox"; + property name="permissionService" inject="id:permissionService@contentbox"; + property name="settingService" inject="id:settingService@contentbox"; + property name="securityService" inject="id:securityService@contentbox"; + property name="moduleService" inject="id:moduleService@contentbox"; + property name="themeService" inject="id:themeService@contentbox"; + property name="widgetService" inject="id:widgetService@contentbox"; + property name="templateService" inject="id:emailtemplateService@contentbox"; + property name="log" inject="logbox:logger:{this}"; + property name="zipUtil" inject="zipUtil@contentbox"; /** * Constructor */ - ContentBoxImporter function init(){ - variables.fileNames = []; + ContentBoxImporter function init() { + variables.fileNames = []; variables.contentBoxPackagePath = ""; - variables.dataServiceMappings = {}; - variables.fileServiceMappings = {}; + variables.dataServiceMappings = {}; + variables.fileServiceMappings = {}; return this; } @@ -60,15 +79,21 @@ component accessors=true { * * @importFile The uploaded .cbox package to import */ - public void function setup( required any importFile ){ + public void function setup( required any importFile ) { try { - var files = variables.zipUtil.list( zipFilePath = arguments.importFile ); + var files = variables.zipUtil.list( zipFilePath = arguments.importFile ); // convert files query to array - var fileList = listToArray( valueList( files.entry ) ).map( function( item ){ - return arguments.item.reReplace( "(\\|\/)", "", "all" ); - } ); + var fileList = listToArray( valueList( files.entry ) ).map( + function( item ) { + return arguments.item.reReplace( + "(\\|\/)", + "", + "all" + ); + } + ); var contentBoxPath = variables.moduleSettings[ "contentbox" ].path; - var customPath = variables.moduleSettings[ "contentbox-custom" ].path; + var customPath = variables.moduleSettings[ "contentbox-custom" ].path; // now set values setFileNames( fileList ); @@ -76,45 +101,53 @@ component accessors=true { // set some cheat mappings variables.dataServiceMappings = { - "Authors" : "authorService", - "Categories" : "categoryService", - "Content Store" : "contentStoreService", - "Menus" : "menuService", - "Permissions" : "permissionService", - "Roles" : "roleService", - "Security Rules" : "securityRuleService", - "Settings" : "settingService", - "Entries" : "entryService", - "Pages" : "pageService" + "Authors" : "authorService", + "Categories" : "categoryService", + "Content Store" : "contentStoreService", + "Menus" : "menuService", + "Permissions" : "permissionService", + "Roles" : "roleService", + "Security Rules": "securityRuleService", + "Settings" : "settingService", + "Entries" : "entryService", + "Pages" : "pageService" }; variables.filePathMappings = { - "Email Templates" : contentBoxPath & "/email_templates", - "Themes" : customPath & "/_themes", - "Media Library" : expandPath( settingService.getSetting( "cb_media_directoryRoot" ) ), - "Modules" : customPath & "/_modules", - "Widgets" : customPath & "/_widgets" + "Email Templates": contentBoxPath & "/email_templates", + "Themes" : customPath & "/_themes", + "Media Library" : expandPath( settingService.getSetting( "cb_media_directoryRoot" ) ), + "Modules" : customPath & "/_modules", + "Widgets" : customPath & "/_widgets" }; - } catch ( any e ) { - log.error( "Error processing ContentBox import package: #e.message# #e.detail#", e ); + } catch (any e) { + log.error( + "Error processing ContentBox import package: #e.message# #e.detail#", + e + ); } } /** * Retrieves contents of descriptor file */ - public any function getDescriptorContents( required boolean asObject = false ){ + public any function getDescriptorContents( required boolean asObject = false ) { var descriptorContents = ""; if ( hasFile( "descriptor.json" ) ) { // if we have a descriptor, extract it variables.zipUtil.extract( - zipFilePath = getContentBoxPackagePath(), - extractPath = getTempDirectory(), - extractFiles = "descriptor.json", - overwriteFiles = true - ); + zipFilePath = getContentBoxPackagePath(), + extractPath = getTempDirectory(), + extractFiles = "descriptor.json", + overwriteFiles = true + ); descriptorContents = fileRead( getTempDirectory() & "descriptor.json" ); - descriptorContents = replaceNoCase( descriptorContents, "null,", "0,", "all" ); + descriptorContents = replaceNoCase( + descriptorContents, + "null,", + "0,", + "all" + ); } return !arguments.asObject ? descriptorContents : deserializeJSON( descriptorContents ); } @@ -124,8 +157,8 @@ component accessors=true { * * @importFile.hint The uploaded .cbox package */ - public boolean function isValid(){ - var isVerified = false; + public boolean function isValid() { + var isVerified = false; var rawDescriptorContent = getDescriptorContents(); // if this is JSON data (as it is expected to be...), deserialize and start verifying package contents if ( isJSON( rawDescriptorContent ) ) { @@ -136,7 +169,9 @@ component accessors=true { isVerified = hasFile( descriptorContent.content[ contentSection ].filename ); } } else { - log.error( "ContentBox package import not valid: #rawDescriptorContent#" ); + log.error( + "ContentBox package import not valid: #rawDescriptorContent#" + ); } return isVerified; } @@ -146,16 +181,16 @@ component accessors=true { * * @overrideContent.hint Whether or not to override existing content with uploaded data (default=false) */ - public string function execute( required boolean overrideContent = false ){ + public string function execute( required boolean overrideContent = false ) { var importLog = createObject( "java", "java.lang.StringBuilder" ).init( - "Starting ContentBox package import with override = #arguments.overrideContent#...
" - ); + "Starting ContentBox package import with override = #arguments.overrideContent#...
" + ); // first, unzip entire package variables.zipUtil.extract( - zipFilePath = getContentBoxPackagePath(), - extractPath = getTempDirectory(), - overwriteFiles = true - ); + zipFilePath = getContentBoxPackagePath(), + extractPath = getTempDirectory(), + overwriteFiles = true + ); // get all content var descriptorContents = getDescriptorContents( true ); // Fix for null priorites, this should go away in later versions @@ -176,16 +211,14 @@ component accessors=true { // Start import transaction transaction { for ( key in priorityOrder ) { - var content = descriptorContents.content[ key ]; + var content = descriptorContents.content[ key ]; var filePath = getTempDirectory() & content.filename; // handle json (data) imports if ( content.format == "json" ) { - var service = variables.dataServiceMappings[ content.name ]; - var importResults = variables[ service ].importFromFile( - importFile = filePath, - override = arguments.overrideContent - ); + var service = variables.dataServiceMappings[ content.name ]; + var importResults = variables[ service ].importFromFile( importFile = filePath, + override = arguments.overrideContent ); importLog.append( importResults ); } @@ -194,10 +227,10 @@ component accessors=true { importLog.append( "
Extracting #content.name#...
" ); var path = variables.filePathMappings[ content.name ]; zipUtil.extract( - zipFilePath = filePath, - extractPath = path, - overwriteFiles = true - ); + zipFilePath = filePath, + extractPath = path, + overwriteFiles = true + ); importLog.append( "Finished extracting #content.name#...
" ); } } @@ -214,9 +247,9 @@ component accessors=true { * * @fileName.hint The file name to validate */ - private boolean function hasFile( required string fileName ){ + private boolean function hasFile( required string fileName ) { // try to find return arrayContains( getFileNames(), arguments.fileName ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/importers/ICBImporter.cfc b/modules/contentbox/models/importers/ICBImporter.cfc index 940eb9f281..a2631606af 100644 --- a/modules/contentbox/models/importers/ICBImporter.cfc +++ b/modules/contentbox/models/importers/ICBImporter.cfc @@ -1,27 +1,27 @@ -/** -******************************************************************************** -ContentBox - A Modular Content Platform -Copyright 2012 by Luis Majano and Ortus Solutions, Corp -www.ortussolutions.com -******************************************************************************** -Apache License, Version 2.0 - -Copyright Since [2012] [Luis Majano and Ortus Solutions,Corp] - -Licensed under the Apache License, Version 2.0 (the "License" ); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -******************************************************************************** -* This is the main importer for importing databases into contentbox -*/ +/** + * ******************************************************************************** + * ContentBox - A Modular Content Platform + * Copyright 2012 by Luis Majano and Ortus Solutions, Corp + * www.ortussolutions.com + * ******************************************************************************** + * Apache License, Version 2.0 + * + * Copyright Since [2012] [Luis Majano and Ortus Solutions,Corp] + * + * Licensed under the Apache License, Version 2.0 (the "License" ); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ******************************************************************************** + * This is the main importer for importing databases into contentbox + */ interface { function execute( @@ -30,7 +30,6 @@ interface { dsnPassword = "", defaultPassword = "", required roleID, - tableprefix = "" + tableprefix = "" ); - -} +} \ No newline at end of file diff --git a/modules/contentbox/models/importers/MachBlogImporter.cfc b/modules/contentbox/models/importers/MachBlogImporter.cfc index efb738a66a..884bc470ac 100644 --- a/modules/contentbox/models/importers/MachBlogImporter.cfc +++ b/modules/contentbox/models/importers/MachBlogImporter.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -6,24 +6,31 @@ * Import a MachBlog database into contentbox */ component implements="ICBImporter" { - // DI property name="categoryService" inject="id:categoryService@contentbox"; + property name="entryService" inject="id:entryService@contentbox"; + property name="pageService" inject="id:pageService@contentbox"; + property name="authorService" inject="id:authorService@contentbox"; + property name="roleService" inject="id:roleService@contentbox"; + property name="commentService" inject="id:commentService@contentbox"; + property name="customFieldService" inject="id:customFieldService@contentbox"; + property name="log" inject="logbox:logger:{this}"; + property name="htmlHelper" inject="HTMLHelper@coldbox"; - property name="bCrypt" inject="BCrypt@BCrypt"; + property name="bCrypt" inject="BCrypt@BCrypt"; /** * Constructor */ - MachBlogImporter function init(){ + MachBlogImporter function init() { return this; } @@ -36,15 +43,19 @@ component implements="ICBImporter" { dsnPassword = "", defaultPassword = "", required roleID, - tableprefix = "" - ){ - var authorMap = {}; - var catMap = {}; - var entryMap = {}; - var pageMap = {}; - var slugMap = {}; + tableprefix = "" + ) { + var authorMap = {}; + var catMap = {}; + var entryMap = {}; + var pageMap = {}; + var slugMap = {}; var pageSlugMap = {}; - var baseDate = createDate( 1970, 1, 1 ); + var baseDate = createDate( + 1970, + 1, + 1 + ); log.info( "Starting import process: #arguments.toString()#" ); @@ -57,10 +68,10 @@ component implements="ICBImporter" { password = arguments.dsnPassword, sql = "select * from #arguments.tablePrefix#machblog_category" ).execute().getResult(); - for ( var x = 1; x lte q.recordcount; x++ ) { + for ( var x = 1; x LTE q.recordcount; x++ ) { var props = { - category : q.category_name[ x ], - slug : htmlHelper.slugify( q.category_name[ x ] ) + category: q.category_name[ x ], + slug : htmlHelper.slugify( q.category_name[ x ] ) }; var cat = categoryService.new( properties = props ); entitySave( cat ); @@ -75,20 +86,20 @@ component implements="ICBImporter" { // Get the default role var defaultRole = roleService.get( arguments.roleID ); // Import Authors - var q = new Query( + var q = new Query( datasource = arguments.dsn, username = arguments.dsnUsername, password = arguments.dsnPassword, sql = "select * from #arguments.tablePrefix#machblog_user" ).execute().getResult(); - for ( var x = 1; x lte q.recordcount; x++ ) { + for ( var x = 1; x LTE q.recordcount; x++ ) { var props = { - email : q.email[ x ], - username : q.email[ x ], - password : bcrypt.hashPassword( defaultPassword ), - isActive : q.is_active[ x ], - firstName : q.first_name[ x ], - lastName : q.last_name[ x ] + email : q.email[ x ], + username : q.email[ x ], + password : bcrypt.hashPassword( defaultPassword ), + isActive : q.is_active[ x ], + firstName: q.first_name[ x ], + lastName : q.last_name[ x ] }; var author = authorService.new( properties = props ); author.setRole( defaultRole ); @@ -117,20 +128,28 @@ component implements="ICBImporter" { sql = "select * from #arguments.tablePrefix#machblog_entry order by dt_modified asc" ).execute().getResult(); - for ( var x = 1; x lte q.recordcount; x++ ) { + for ( var x = 1; x LTE q.recordcount; x++ ) { var published = true; if ( !q.is_active[ x ] ) { published = false; } var props = { - title : q.title[ x ], - slug : htmlHelper.slugify( q.title[ x ] ), - content : q.body[ x ] & q.more_body[ x ], - excerpt : q.body[ x ], - publishedDate : dateAdd( "s", q.dt_posted[ x ] / 1000, baseDate ), - createdDate : dateAdd( "s", q.dt_created[ x ] / 1000, baseDate ), - isPublished : published, - allowComments : q.allow_comments[ x ] + title : q.title[ x ], + slug : htmlHelper.slugify( q.title[ x ] ), + content : q.body[ x ] & q.more_body[ x ], + excerpt : q.body[ x ], + publishedDate: dateAdd( + "s", + q.dt_posted[ x ] / 1000, + baseDate + ), + createdDate: dateAdd( + "s", + q.dt_created[ x ] / 1000, + baseDate + ), + isPublished : published, + allowComments: q.allow_comments[ x ] }; // slug checks @@ -147,10 +166,10 @@ component implements="ICBImporter" { var entry = entryService.new( properties = props ); // Add content versionized! entry.addNewContentVersion( - content = props.content, - changelog = "Imported content", - author = authorService.get( authorMap[ q.created_by_id[ x ] ] ) - ); + content = props.content, + changelog = "Imported content", + author = authorService.get( authorMap[ q.created_by_id[ x ] ] ) + ); entry.setCreator( authorService.get( authorMap[ q.created_by_id[ x ] ] ) ); // entry categories var qCategories = new Query( @@ -160,8 +179,11 @@ component implements="ICBImporter" { sql = "select * from #arguments.tablePrefix#machblog_entry_category as category where category.entry_id = '#q.entry_id[ x ]#'" ).execute().getResult(); var aCategories = []; - for ( var y = 1; y lte qCategories.recordcount; y++ ) { - arrayAppend( aCategories, categoryService.get( catMap[ qCategories.category_id[ y ] ] ) ); + for ( var y = 1; y LTE qCategories.recordcount; y++ ) { + arrayAppend( + aCategories, + categoryService.get( catMap[ qCategories.category_id[ y ] ] ) + ); } entry.setCategories( aCategories ); @@ -179,19 +201,19 @@ component implements="ICBImporter" { password = arguments.dsnPassword, sql = "select * from #arguments.tablePrefix#machblog_comment as comment where comment.entry_id = '#q.entry_id[ x ]#' order by dt_created asc" ).execute().getResult(); - for ( var y = 1; y lte qComments.recordcount; y++ ) { + for ( var y = 1; y LTE qComments.recordcount; y++ ) { var props = { - content : qComments.comment[ y ], - author : qComments.name[ y ], - authorIP : qComments.ip_created[ y ], - authorEmail : qComments.email[ y ], - authorURL : qComments.url[ y ], - createdDate : dateAdd( + content : qComments.comment[ y ], + author : qComments.name[ y ], + authorIP : qComments.ip_created[ y ], + authorEmail: qComments.email[ y ], + authorURL : qComments.url[ y ], + createdDate: dateAdd( "s", qComments.dt_created[ y ] / 1000, baseDate ), - isApproved : qComments.is_active[ y ] + isApproved: qComments.is_active[ y ] }; var comment = commentService.new( properties = props ); comment.setRelatedContent( entry ); @@ -203,16 +225,14 @@ component implements="ICBImporter" { log.info( "Entry imported: #entry.getTitle()#" ); } log.info( "Entries imported successfully!" ); - } - // end of try - catch ( any e ) { + }// end of try + catch (any e) { log.error( "Error importing blog: #e.message# #e.detail#", e ); rethrow; } // Commit All entities - transaction action="commit" { - } + transaction action="commit"; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/importers/MangoImporter.cfc b/modules/contentbox/models/importers/MangoImporter.cfc index b8564f4325..95f1e1bc1d 100644 --- a/modules/contentbox/models/importers/MangoImporter.cfc +++ b/modules/contentbox/models/importers/MangoImporter.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -6,24 +6,31 @@ * Import a mango database into contentbox */ component implements="contentbox.models.importers.ICBImporter" { - // DI property name="categoryService" inject="id:categoryService@contentbox"; + property name="entryService" inject="id:entryService@contentbox"; + property name="pageService" inject="id:pageService@contentbox"; + property name="authorService" inject="id:authorService@contentbox"; + property name="roleService" inject="id:roleService@contentbox"; + property name="commentService" inject="id:commentService@contentbox"; + property name="customFieldService" inject="id:customFieldService@contentbox"; + property name="log" inject="logbox:logger:{this}"; + property name="htmlHelper" inject="HTMLHelper@coldbox"; - property name="bCrypt" inject="BCrypt@BCrypt"; + property name="bCrypt" inject="BCrypt@BCrypt"; /** * Constructor */ - MangoImporter function init(){ + MangoImporter function init() { return this; } @@ -36,13 +43,13 @@ component implements="contentbox.models.importers.ICBImporter" { dsnPassword = "", defaultPassword = "", required roleID, - tableprefix = "" - ){ - var authorMap = {}; - var catMap = {}; - var entryMap = {}; - var pageMap = {}; - var slugMap = {}; + tableprefix = "" + ) { + var authorMap = {}; + var catMap = {}; + var entryMap = {}; + var pageMap = {}; + var slugMap = {}; var pageSlugMap = {}; log.info( "Starting import process: #arguments.toString()#" ); @@ -56,9 +63,9 @@ component implements="contentbox.models.importers.ICBImporter" { password = arguments.dsnPassword, sql = "select * from #arguments.tablePrefix#category" ).execute().getResult(); - for ( var x = 1; x lte q.recordcount; x++ ) { - var props = { category : q.title[ x ], slug : q.name[ x ] }; - var cat = categoryService.new( properties = props ); + for ( var x = 1; x LTE q.recordcount; x++ ) { + var props = { category: q.title[ x ], slug: q.name[ x ] }; + var cat = categoryService.new( properties = props ); var exists = categoryService.findAllBySlug( q.name[ x ] ); if ( arrayLen( exists ) ) { @@ -78,20 +85,26 @@ component implements="contentbox.models.importers.ICBImporter" { // Get the default role var defaultRole = roleService.get( arguments.roleID ); // Import Authors - var q = new Query( + var q = new Query( datasource = arguments.dsn, username = arguments.dsnUsername, password = arguments.dsnPassword, sql = "select * from #arguments.tablePrefix#author" ).execute().getResult(); - for ( var x = 1; x lte q.recordcount; x++ ) { + for ( var x = 1; x LTE q.recordcount; x++ ) { var props = { - email : q.email[ x ], - username : q.username[ x ], - password : bcrypt.hashPassword( defaultPassword ), - isActive : 1, - firstName : listFirst( q.name[ x ], " " ), - lastName : trim( replaceNoCase( q.name[ x ], listFirst( q.name[ x ], " " ), "" ) ) + email : q.email[ x ], + username : q.username[ x ], + password : bcrypt.hashPassword( defaultPassword ), + isActive : 1, + firstName: listFirst( q.name[ x ], " " ), + lastName : trim( + replaceNoCase( + q.name[ x ], + listFirst( q.name[ x ], " " ), + "" + ) + ) }; var author = authorService.new( properties = props ); author.setRole( defaultRole ); @@ -118,23 +131,23 @@ component implements="contentbox.models.importers.ICBImporter" { where me.id = mp.id order by mp.hierarchy" ).execute().getResult(); - for ( var x = 1; x lte qPages.recordcount; x++ ) { + for ( var x = 1; x LTE qPages.recordcount; x++ ) { // Get properties var published = true; - if ( qPages.status[ x ] neq "published" ) { + if ( qPages.status[ x ] NEQ "published" ) { published = false; } var props = { - title : qPages.title[ x ], - slug : qPages.name[ x ], - content : qPages.content[ x ], - excerpt : qPages.excerpt[ x ], - publishedDate : qPages.last_modified[ x ], - createdDate : qPages.last_modified[ x ], - isPublished : published, - allowComments : qPages.comments_allowed[ x ], - order : qPages.sort_order[ x ], - layout : "pages" + title : qPages.title[ x ], + slug : qPages.name[ x ], + content : qPages.content[ x ], + excerpt : qPages.excerpt[ x ], + publishedDate: qPages.last_modified[ x ], + createdDate : qPages.last_modified[ x ], + isPublished : published, + allowComments: qPages.comments_allowed[ x ], + order : qPages.sort_order[ x ], + layout : "pages" }; // slug checks @@ -151,10 +164,10 @@ component implements="contentbox.models.importers.ICBImporter" { var page = pageService.new( properties = props ); // Add content versionized! page.addNewContentVersion( - content = props.content, - changelog = "Imported content", - author = authorService.get( authorMap[ qPages.author_id[ x ] ] ) - ); + content = props.content, + changelog = "Imported content", + author = authorService.get( authorMap[ qPages.author_id[ x ] ] ) + ); page.setCreator( authorService.get( authorMap[ qPages.author_id[ x ] ] ) ); // Custom Fields log.info( "Starting to import Page Custom Fields...." ); @@ -164,10 +177,10 @@ component implements="contentbox.models.importers.ICBImporter" { password = arguments.dsnPassword, sql = "select * from #arguments.tablePrefix#entry_custom_field as cf where cf.entry_id = '#qPages.id[ x ]#'" ).execute().getResult(); - for ( var y = 1; y lte qCustomFields.recordcount; y++ ) { + for ( var y = 1; y LTE qCustomFields.recordcount; y++ ) { var props = { - key : qCustomFields.name[ y ], - value : qCustomFields.field_value[ y ] + key : qCustomFields.name[ y ], + value: qCustomFields.field_value[ y ] }; var thisCustomField = customFieldService.new( properties = props ); page.addCustomField( thisCustomField ); @@ -186,15 +199,15 @@ component implements="contentbox.models.importers.ICBImporter" { password = arguments.dsnPassword, sql = "select * from #arguments.tablePrefix#comment as mc where mc.entry_id = '#qPages.id[ x ]#'" ).execute().getResult(); - for ( var y = 1; y lte qComments.recordcount; y++ ) { + for ( var y = 1; y LTE qComments.recordcount; y++ ) { var props = { - content : qComments.content[ y ], - author : qComments.creator_name[ y ], - authorIP : "127.0.0.1", - authorEmail : qComments.creator_email[ y ], - authorURL : qComments.creator_url[ y ], - createdDate : qComments.created_on[ y ], - isApproved : qComments.approved[ y ] + content : qComments.content[ y ], + author : qComments.creator_name[ y ], + authorIP : "127.0.0.1", + authorEmail: qComments.creator_email[ y ], + authorURL : qComments.creator_url[ y ], + createdDate: qComments.created_on[ y ], + isApproved : qComments.approved[ y ] }; var comment = commentService.new( properties = props ); comment.setRelatedContent( page ); @@ -227,20 +240,20 @@ component implements="contentbox.models.importers.ICBImporter" { ) order by last_modified asc" ).execute().getResult(); - for ( var x = 1; x lte q.recordcount; x++ ) { + for ( var x = 1; x LTE q.recordcount; x++ ) { var published = true; - if ( q.status[ x ] neq "published" ) { + if ( q.status[ x ] NEQ "published" ) { published = false; } var props = { - title : q.title[ x ], - slug : q.name[ x ], - content : q.content[ x ], - excerpt : q.excerpt[ x ], - publishedDate : q.last_modified[ x ], - createdDate : q.last_modified[ x ], - isPublished : published, - allowComments : q.comments_allowed[ x ] + title : q.title[ x ], + slug : q.name[ x ], + content : q.content[ x ], + excerpt : q.excerpt[ x ], + publishedDate: q.last_modified[ x ], + createdDate : q.last_modified[ x ], + isPublished : published, + allowComments: q.comments_allowed[ x ] }; // slug checks @@ -257,10 +270,10 @@ component implements="contentbox.models.importers.ICBImporter" { var entry = entryService.new( properties = props ); // Add content versionized! entry.addNewContentVersion( - content = props.content, - changelog = "Imported content", - author = authorService.get( authorMap[ q.author_id[ x ] ] ) - ); + content = props.content, + changelog = "Imported content", + author = authorService.get( authorMap[ q.author_id[ x ] ] ) + ); entry.setCreator( authorService.get( authorMap[ q.author_id[ x ] ] ) ); // entry categories var qCategories = new Query( @@ -270,8 +283,11 @@ component implements="contentbox.models.importers.ICBImporter" { sql = "select * from #arguments.tablePrefix#post_category as mp where mp.post_id = '#q.id[ x ]#'" ).execute().getResult(); var aCategories = []; - for ( var y = 1; y lte qCategories.recordcount; y++ ) { - arrayAppend( aCategories, categoryService.get( catMap[ qCategories.category_id[ y ] ] ) ); + for ( var y = 1; y LTE qCategories.recordcount; y++ ) { + arrayAppend( + aCategories, + categoryService.get( catMap[ qCategories.category_id[ y ] ] ) + ); } entry.setCategories( aCategories ); @@ -282,10 +298,10 @@ component implements="contentbox.models.importers.ICBImporter" { password = arguments.dsnPassword, sql = "select * from #arguments.tablePrefix#entry_custom_field as cf where cf.entry_id = '#q.id[ x ]#'" ).execute().getResult(); - for ( var y = 1; y lte qCustomFields.recordcount; y++ ) { + for ( var y = 1; y LTE qCustomFields.recordcount; y++ ) { var props = { - key : qCustomFields.name[ y ], - value : qCustomFields.field_value[ y ] + key : qCustomFields.name[ y ], + value: qCustomFields.field_value[ y ] }; var thisCustomField = customFieldService.new( properties = props ); entry.addCustomField( thisCustomField ); @@ -303,15 +319,15 @@ component implements="contentbox.models.importers.ICBImporter" { password = arguments.dsnPassword, sql = "select * from #arguments.tablePrefix#comment as mc where mc.entry_id = '#q.id[ x ]#'" ).execute().getResult(); - for ( var y = 1; y lte qComments.recordcount; y++ ) { + for ( var y = 1; y LTE qComments.recordcount; y++ ) { var props = { - content : qComments.content[ y ], - author : qComments.creator_name[ y ], - authorIP : "127.0.0.1", - authorEmail : qComments.creator_email[ y ], - authorURL : qComments.creator_url[ y ], - createdDate : qComments.created_on[ y ], - isApproved : qComments.approved[ y ] + content : qComments.content[ y ], + author : qComments.creator_name[ y ], + authorIP : "127.0.0.1", + authorEmail: qComments.creator_email[ y ], + authorURL : qComments.creator_url[ y ], + createdDate: qComments.created_on[ y ], + isApproved : qComments.approved[ y ] }; var comment = commentService.new( properties = props ); comment.setRelatedContent( entry ); @@ -323,16 +339,14 @@ component implements="contentbox.models.importers.ICBImporter" { log.info( "Entry imported: #entry.getTitle()#" ); } log.info( "Entries imported successfully!" ); - } - // end of try - catch ( any e ) { + }// end of try + catch (any e) { log.error( "Error importing blog: #e.message# #e.detail#", e ); rethrow; } // Commit All entities - transaction action="commit" { - } + transaction action="commit"; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/importers/WordpressImporter.cfc b/modules/contentbox/models/importers/WordpressImporter.cfc index e5e4603d11..92cf518036 100644 --- a/modules/contentbox/models/importers/WordpressImporter.cfc +++ b/modules/contentbox/models/importers/WordpressImporter.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -6,24 +6,31 @@ * Import a WordPress database into contentbox */ component implements="contentbox.models.importers.ICBImporter" { - // DI property name="categoryService" inject="id:categoryService@contentbox"; + property name="entryService" inject="id:entryService@contentbox"; + property name="pageService" inject="id:pageService@contentbox"; + property name="authorService" inject="id:authorService@contentbox"; + property name="roleService" inject="id:roleService@contentbox"; + property name="commentService" inject="id:commentService@contentbox"; + property name="customFieldService" inject="id:customFieldService@contentbox"; + property name="log" inject="logbox:logger:{this}"; + property name="htmlHelper" inject="HTMLHelper@coldbox"; - property name="bCrypt" inject="BCrypt@BCrypt"; + property name="bCrypt" inject="BCrypt@BCrypt"; /** * Constructor */ - WordPressImporter function init(){ + WordPressImporter function init() { return this; } @@ -36,13 +43,13 @@ component implements="contentbox.models.importers.ICBImporter" { dsnPassword = "", defaultPassword = "", required roleID, - tableprefix = "" - ){ - var authorMap = {}; - var catMap = {}; - var entryMap = {}; - var pageMap = {}; - var slugMap = {}; + tableprefix = "" + ) { + var authorMap = {}; + var catMap = {}; + var entryMap = {}; + var pageMap = {}; + var slugMap = {}; var pageSlugMap = {}; log.info( "Starting import process: #arguments.toString()#" ); @@ -56,9 +63,9 @@ component implements="contentbox.models.importers.ICBImporter" { password = arguments.dsnPassword, sql = "select * from #arguments.tableprefix#_terms a, #arguments.tableprefix#_term_taxonomy b where a.term_id = b.term_id AND b.taxonomy = 'category'" ).execute().getResult(); - for ( var x = 1; x lte q.recordcount; x++ ) { - var props = { category : q.name[ x ], slug : q.slug[ x ] }; - var cat = categoryService.new( properties = props ); + for ( var x = 1; x LTE q.recordcount; x++ ) { + var props = { category: q.name[ x ], slug: q.slug[ x ] }; + var cat = categoryService.new( properties = props ); var exists = categoryService.findAllBySlug( q.slug[ x ] ); if ( arrayLen( exists ) ) { @@ -78,22 +85,22 @@ component implements="contentbox.models.importers.ICBImporter" { // Get the default role var defaultRole = roleService.get( arguments.roleID ); // Import Authors - var q = new Query( + var q = new Query( datasource = arguments.dsn, username = arguments.dsnUsername, password = arguments.dsnPassword, sql = "select * from #arguments.tableprefix#_users" ).execute().getResult(); var selectedRole = roleService.get( arguments.roleID ); - for ( var x = 1; x lte q.recordcount; x++ ) { + for ( var x = 1; x LTE q.recordcount; x++ ) { var props = { - email : q.user_email[ x ], - username : q.user_login[ x ], - password : bcrypt.hashPassword( defaultPassword ), - isActive : 1, - role : selectedRole, - firstName : listFirst( q.display_name[ x ], " " ), - lastName : trim( + email : q.user_email[ x ], + username : q.user_login[ x ], + password : bcrypt.hashPassword( defaultPassword ), + isActive : 1, + role : selectedRole, + firstName: listFirst( q.display_name[ x ], " " ), + lastName : trim( replaceNoCase( q.display_name[ x ], listFirst( q.display_name[ x ], " " ), @@ -124,27 +131,27 @@ component implements="contentbox.models.importers.ICBImporter" { password = arguments.dsnPassword, sql = "select id,post_title AS title,post_name AS name,post_content AS content,post_status,comment_status,post_password,post_date AS last_modified,post_author AS author_id from #arguments.tableprefix#_posts where post_type='page'" ).execute().getResult(); - for ( var x = 1; x lte qPages.recordcount; x++ ) { + for ( var x = 1; x LTE qPages.recordcount; x++ ) { // Get properties - var published = true; + var published = true; var commentStatus = true; - if ( trim( qPages.post_status[ x ] ) neq "publish" ) { + if ( trim( qPages.post_status[ x ] ) NEQ "publish" ) { published = false; } - if ( qPages.comment_status[ x ] neq "open" ) { + if ( qPages.comment_status[ x ] NEQ "open" ) { commentSatus = false; } var props = { - title : qPages.title[ x ], - slug : qPages.name[ x ], - content : fixWordPressContent( qPages.content[ x ] ), - excerpt : "", - publishedDate : qPages.last_modified[ x ], - createdDate : qPages.last_modified[ x ], - isPublished : published, - allowComments : commentStatus, - layout : "pages" + title : qPages.title[ x ], + slug : qPages.name[ x ], + content : fixWordPressContent( qPages.content[ x ] ), + excerpt : "", + publishedDate: qPages.last_modified[ x ], + createdDate : qPages.last_modified[ x ], + isPublished : published, + allowComments: commentStatus, + layout : "pages" }; var moreLoc = findNoCase( "", props.content ); @@ -166,24 +173,24 @@ component implements="contentbox.models.importers.ICBImporter" { var page = pageService.new( properties = props ); // Add content versionized! page.addNewContentVersion( - content = props.content, - changelog = "Imported content", - author = authorService.get( authorMap[ qPages.author_id[ x ] ] ) - ); + content = props.content, + changelog = "Imported content", + author = authorService.get( authorMap[ qPages.author_id[ x ] ] ) + ); // Add Creator page.setCreator( authorService.get( authorMap[ qPages.author_id[ x ] ] ) ); // Save page and store in reference map pageMap[ qPages.id[ x ] ] = page; - var c = pageService.newCriteria(); + var c = pageService.newCriteria(); var counter = 1; - var count = new query( + var count = new query( sql = "SELECT COUNT(*) AS ct FROM cb_content WHERE contentType = 'page' AND slug = '#page.getSlug()#';" ).execute().getResult()[ "ct" ]; do { var count = new query( sql = "SELECT COUNT(*) AS ct FROM cb_content WHERE contentType = 'page' AND slug = '#page.getSlug()#';" ).execute().getResult()[ "ct" ]; - if ( count eq 0 ) { + if ( count EQ 0 ) { break; } // verify no slug exists & append if it does @@ -202,15 +209,15 @@ component implements="contentbox.models.importers.ICBImporter" { AND comment_approved <> 'spam'" ).execute().getResult(); var aComments = []; - for ( var y = 1; y lte qComments.recordcount; y++ ) { + for ( var y = 1; y LTE qComments.recordcount; y++ ) { var props = { - content : qComments.comment_content[ y ], - author : qComments.comment_author[ y ], - authorIP : "127.0.0.1", - authorEmail : qComments.comment_author_email[ y ], - authorURL : qComments.comment_author_url[ y ], - createdDate : qComments.comment_date[ y ], - isApproved : qComments.comment_approved[ y ] + content : qComments.comment_content[ y ], + author : qComments.comment_author[ y ], + authorIP : "127.0.0.1", + authorEmail: qComments.comment_author_email[ y ], + authorURL : qComments.comment_author_url[ y ], + createdDate: qComments.comment_date[ y ], + isApproved : qComments.comment_approved[ y ] }; var comment = commentService.new( properties = props ); comment.setRelatedContent( page ); @@ -234,27 +241,27 @@ component implements="contentbox.models.importers.ICBImporter" { password = arguments.dsnPassword, sql = "select id,post_title AS title,post_name AS name,post_content AS content,post_status,comment_status,post_password,post_date AS last_modified,post_author AS author_id from #arguments.tableprefix#_posts where post_type='post'" ).execute().getResult(); - for ( var x = 1; x lte qEntries.recordcount; x++ ) { + for ( var x = 1; x LTE qEntries.recordcount; x++ ) { // Get properties - var published = true; + var published = true; var commentStatus = true; - if ( trim( qEntries.post_status[ x ] ) neq "publish" ) { + if ( trim( qEntries.post_status[ x ] ) NEQ "publish" ) { published = false; } - if ( qEntries.comment_status[ x ] neq "open" ) { + if ( qEntries.comment_status[ x ] NEQ "open" ) { commentSatus = false; } var props = { - title : qEntries.title[ x ], - slug : qEntries.name[ x ], - content : fixWordPressContent( qEntries.content[ x ] ), - excerpt : "", - publishedDate : qEntries.last_modified[ x ], - createdDate : qEntries.last_modified[ x ], - isPublished : published, - allowComments : commentStatus, - layout : "entries" + title : qEntries.title[ x ], + slug : qEntries.name[ x ], + content : fixWordPressContent( qEntries.content[ x ] ), + excerpt : "", + publishedDate: qEntries.last_modified[ x ], + createdDate : qEntries.last_modified[ x ], + isPublished : published, + allowComments: commentStatus, + layout : "entries" }; var moreLoc = findNoCase( "", props.content ); @@ -276,24 +283,24 @@ component implements="contentbox.models.importers.ICBImporter" { var entry = entryService.new( properties = props ); // Add content versionized! entry.addNewContentVersion( - content = props.content, - changelog = "Imported content", - author = authorService.get( authorMap[ qEntries.author_id[ x ] ] ) - ); + content = props.content, + changelog = "Imported content", + author = authorService.get( authorMap[ qEntries.author_id[ x ] ] ) + ); entry.setCreator( authorService.get( authorMap[ qEntries.author_id[ x ] ] ) ); // Save entry and store in reference map entryMap[ qEntries.id[ x ] ] = entry; - var c = entryService.newCriteria(); + var c = entryService.newCriteria(); var counter = 1; - var count = new query( + var count = new query( sql = "SELECT COUNT(*) AS ct FROM cb_content WHERE contentType = 'post' AND slug = '#entry.getSlug()#';" ).execute().getResult()[ "ct" ]; do { var count = new query( sql = "SELECT COUNT(*) AS ct FROM cb_content WHERE contentType = 'post' AND slug = '#entry.getSlug()#';" ).execute().getResult()[ "ct" ]; - if ( count eq 0 ) { + if ( count EQ 0 ) { break; } // verify no slug exists & append if it does @@ -319,7 +326,7 @@ component implements="contentbox.models.importers.ICBImporter" { sql = thisSQL ).execute().getResult(); var aCategories = []; - for ( var y = 1; y lte qCategories.recordcount; y++ ) { + for ( var y = 1; y LTE qCategories.recordcount; y++ ) { arrayAppend( aCategories, categoryService.get( catMap[ qCategories.term_id[ y ] ] ) ); } entry.setCategories( aCategories ); @@ -336,15 +343,15 @@ component implements="contentbox.models.importers.ICBImporter" { ).execute().getResult(); var aComments = []; - for ( var y = 1; y lte qComments.recordcount; y++ ) { + for ( var y = 1; y LTE qComments.recordcount; y++ ) { var props = { - content : qComments.comment_content[ y ], - author : qComments.comment_author[ y ], - authorIP : "127.0.0.1", - authorEmail : qComments.comment_author_email[ y ], - authorURL : qComments.comment_author_url[ y ], - createdDate : qComments.comment_date[ y ], - isApproved : qComments.comment_approved[ y ] + content : qComments.comment_content[ y ], + author : qComments.comment_author[ y ], + authorIP : "127.0.0.1", + authorEmail: qComments.comment_author_email[ y ], + authorURL : qComments.comment_author_url[ y ], + createdDate: qComments.comment_date[ y ], + isApproved : qComments.comment_approved[ y ] }; var comment = commentService.new( properties = props ); comment.setRelatedContent( entry ); @@ -358,41 +365,114 @@ component implements="contentbox.models.importers.ICBImporter" { // Save entry entitySave( entry ); } - } - // end of try - catch ( any e ) { + }// end of try + catch (any e) { log.error( "Error importing blog: #e.message# #e.detail#", e ); rethrow; } // Commit All entities - transaction action="commit" { - } + transaction action="commit"; } - private function fixWordPressContent( required string str ){ + private function fixWordPressContent( required string str ) { var myStr = trim( arguments.str ); - myStr = replaceNoCase( myStr, chr( 10 ), "

", "all" ); - myStr = replaceNoCase( myStr, chr( 13 ), "

", "all" ); - myStr = replaceNoCase( myStr, "

", "", "all" ); - myStr = replaceNoCase( myStr, "

", "", "all" ); - myStr = replaceNoCase( myStr, "

", "", "all" ); - myStr = replaceNoCase( myStr, "

", "", "all" ); - myStr = replaceNoCase( myStr, "

", "", "all" ); - myStr = replaceNoCase( myStr, "

", "", "all" ); - - myStr = replaceNoCase( myStr, "

", "", "all" ); - - myStr = replaceNoCase( myStr, "

", "", "all" ); - - myStr = reReplace( myStr, "\[caption[^\]]*\]", "", "all" ); - myStr = replaceNoCase( myStr, "[/caption]", "", "all" ); + myStr = replaceNoCase( + myStr, + chr( 10 ), + "

", + "all" + ); + myStr = replaceNoCase( + myStr, + chr( 13 ), + "

", + "all" + ); + myStr = replaceNoCase( + myStr, + "

", + "", + "all" + ); + myStr = replaceNoCase( + myStr, + "

", + "", + "all" + ); + myStr = replaceNoCase( + myStr, + "

", + "", + "all" + ); + myStr = replaceNoCase( + myStr, + "

", + "", + "all" + ); + myStr = replaceNoCase( + myStr, + "

", + "", + "all" + ); + myStr = replaceNoCase( + myStr, + "

", + "", + "all" + ); + + myStr = replaceNoCase( + myStr, + "

", + "", + "all" + ); + + myStr = replaceNoCase( + myStr, + "

", + "", + "all" + ); + + myStr = reReplace( + myStr, + "\[caption[^\]]*\]", + "", + "all" + ); + myStr = replaceNoCase( + myStr, + "[/caption]", + "", + "all" + ); return myStr; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/media/BaseProvider.cfc b/modules/contentbox/models/media/BaseProvider.cfc index ae2d8dbc45..49f8f62360 100644 --- a/modules/contentbox/models/media/BaseProvider.cfc +++ b/modules/contentbox/models/media/BaseProvider.cfc @@ -1,10 +1,13 @@ component accessors="true" singleton { - // Dependecnies property name="mediaService" inject="mediaService@contentbox"; + property name="log" inject="logbox:logger:{this}"; + property name="cbfs" inject="DiskService@cbfs"; + property name="templateCache" inject="cachebox:template"; + /** * The internal name of the provider */ @@ -25,25 +28,28 @@ component accessors="true" singleton { * * @mediaPath.hint the media path to verify if it exists */ - public boolean function mediaExists( required mediaPath ){ - return templateCache.getOrSet( "provider_item_exists_#hash( mediaPath )#", function(){ - var cbfsParts = listToArray( mediaPath, ":" ); - return cbfsParts.len() > 1 - ? cbfs.get( cbfsParts[ 1 ] ).exists( cbfsParts[ 2 ] ) - : fileExists( getRealMediaPath( mediaPath ) ); - } ); + public boolean function mediaExists( required mediaPath ) { + return templateCache.getOrSet( + "provider_item_exists_#hash( mediaPath )#", + function() { + var cbfsParts = listToArray( mediaPath, ":" ); + return cbfsParts.len() > 1 + ? cbfs.get( cbfsParts[ 1 ] ).exists( cbfsParts[ 2 ] ) + : fileExists( getRealMediaPath( mediaPath ) ); + } + ); } /************************************** Package Utility Methods *********************************************/ - package function getPublicURL( required mediaPath ){ + package function getPublicURL( required mediaPath ) { var cbfsParts = listToArray( arguments.mediaPath, ":" ); return cbfsParts.len() > 1 - ? cbfs.get( cbfsParts[ 1 ] ).url( cbfsParts[ 2 ] ) - : cbfs.get( "contentbox" ).url( arguments.mediaPath ); + ? cbfs.get( cbfsParts[ 1 ] ).url( cbfsParts[ 2 ] ) + : cbfs.get( "contentbox" ).url( arguments.mediaPath ); } - package function getRealMediaPath( required mediaPath ){ + package function getRealMediaPath( required mediaPath ) { return mediaService.getCoreMediaRoot( absolute = true ) & "/#arguments.mediaPath#"; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/media/CFContentMediaProvider.cfc b/modules/contentbox/models/media/CFContentMediaProvider.cfc index 549ea4dbad..b3e6eb3d49 100644 --- a/modules/contentbox/models/media/CFContentMediaProvider.cfc +++ b/modules/contentbox/models/media/CFContentMediaProvider.cfc @@ -5,15 +5,14 @@ * --- * Deliver file via cfcontent */ -component accessors="true" extends="BaseProvider" singleton { - +component accessors="true" extends ="BaseProvider" singleton { property name="requestService" inject="coldbox:requestService"; /** * Constructor */ - any function init(){ - variables.name = "CFContentMediaProvider"; + any function init() { + variables.name = "CFContentMediaProvider"; variables.displayName = "CF Content Media Provider"; variables.description = "This provider uses the ColdFusion cfcontent tag to deliver and stream files securely to the user."; return this; @@ -24,21 +23,24 @@ component accessors="true" extends="BaseProvider" singleton { * * @mediaPath.hint the media path to deliver back to the user */ - any function deliverMedia( required mediaPath ){ + any function deliverMedia( required mediaPath ) { var cbfsParts = listToArray( arguments.mediaPath, ":" ); - var context = variables.requestService.getContext(); + var context = variables.requestService.getContext(); if ( cbfsParts.len() > 1 ) { - return variables.cbfs.get( cbfsParts[ 1 ] ).download( cbfsParts[ 2 ] ); + return variables + .cbfs + .get( cbfsParts[ 1 ] ) + .download( cbfsParts[ 2 ] ); } else { - var file = getRealMediaPath( arguments.mediaPath ); + var file = getRealMediaPath( arguments.mediaPath ); var mimeType = fileGetMimeType( file ); context.sendFile( - file = file, - disposition = "inline", - mimeType = mimeType, - extension = listLast( arguments.mediaPath, "." ) - ); + file = file, + disposition = "inline", + mimeType = mimeType, + extension = listLast( arguments.mediaPath, "." ) + ); } } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/media/ForwardMediaProvider.cfc b/modules/contentbox/models/media/ForwardMediaProvider.cfc index 0612c899b8..9782661342 100644 --- a/modules/contentbox/models/media/ForwardMediaProvider.cfc +++ b/modules/contentbox/models/media/ForwardMediaProvider.cfc @@ -5,13 +5,13 @@ * --- * Deliver file via pagecontext forward */ -component accessors="true" extends="BaseProvider" singleton { +component accessors="true" extends ="BaseProvider" singleton { /** * Constructor */ - any function init(){ - variables.name = "ForwardMediaProvider"; + any function init() { + variables.name = "ForwardMediaProvider"; variables.displayName = "Forward Media Provider"; variables.description = "This provider will forward to the real physical location in the server for the media path requested via the internal servlet page context, so no real media path URL will be shown to the user. Use only if the media root is web accessible and a relative web root path, so double check your media root."; @@ -23,29 +23,27 @@ component accessors="true" extends="BaseProvider" singleton { * * @mediaPath.hint the media path to deliver back to the user */ - any function deliverMedia( required mediaPath ){ + any function deliverMedia( required mediaPath ) { var publicURL = getPublicURL( arguments.mediaPath ); var connection = createObject( "java", "java.net.URL" ).init( publicURL ).openConnection(); - var response = structKeyExists( server, "lucee" ) ? getPageContext().getResponse() : getPageContext() - .getResponse() - .getResponse(); + var response = structKeyExists( server, "lucee" ) + ? getPageContext().getResponse() + : getPageContext().getResponse().getResponse(); var outputStream = response.getOutputStream(); try { var inputStream = connection.getInputStream(); - } catch ( any e ) { + } catch (any e) { connection.disconnect(); rethrow; } - response.setStatus( connection.getResponseCode(), connection.getResponseMessage() ); - response.setContentType( - createObject( "java", "java.net.URLConnection" ).guessContentTypeFromName( listLast( publicURL, "/" ) ) - ); + response.setContentType( createObject( "java", + "java.net.URLConnection" ).guessContentTypeFromName( listLast( publicURL, "/" ) ) ); if ( connection.getResponseCode() > 399 ) { response.flushBuffer(); @@ -57,26 +55,32 @@ component accessors="true" extends="BaseProvider" singleton { while ( true ) { try { var remaining = inputStream.available(); - if ( remaining == 0 ) break; + if ( remaining == 0 ) { + break; + } var chunkSize = remaining > 1024 ? 1024 : remaining; - var buffer = createObject( "java", "java.nio.ByteBuffer" ).allocate( chunkSize ); + var buffer = createObject( "java", "java.nio.ByteBuffer" ).allocate( chunkSize ); var bytesRead = inputStream.read( buffer.array() ); outputStream.write( - buffer.array(), - javacast( "int", 0 ), - bytesRead - ); + buffer.array(), + javacast( "int", 0 ), + bytesRead + ); outputStream.flush(); - } catch ( java.net.SocketException e ) { + } catch (java.net.SocketException e) { // Connection reset by peer: socket write error break; } } } finally { - if ( !isNull( inputStream ) ) inputStream.close(); - if ( !isNull( connection ) ) connection.disconnect(); + if ( !isNull( inputStream ) ) { + inputStream.close(); + } + if ( !isNull( connection ) ) { + connection.disconnect(); + } response.flushBuffer(); } } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/media/MediaService.cfc b/modules/contentbox/models/media/MediaService.cfc index cb6179f75f..cbd142b96c 100644 --- a/modules/contentbox/models/media/MediaService.cfc +++ b/modules/contentbox/models/media/MediaService.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -6,13 +6,13 @@ * Manage's the system's media files */ component accessors="true" singleton { - /** * -------------------------------------------------------------------------- * DI * -------------------------------------------------------------------------- */ property name="log" inject="logbox:logger:{this}"; + property name="settingService" inject="settingservice@contentbox"; /** @@ -25,7 +25,6 @@ component accessors="true" singleton { * ContentBox Providers Map */ property name="providers" type="struct"; - /** * -------------------------------------------------------------------------- * Static @@ -40,7 +39,7 @@ component accessors="true" singleton { * * @wirebox.inject wirebox */ - MediaService function init( required wirebox ){ + MediaService function init( required wirebox ) { // The registered system media providers variables.providers = {}; @@ -58,7 +57,7 @@ component accessors="true" singleton { /** * Get the default system media provider name as a string */ - function getDefaultProviderName(){ + function getDefaultProviderName() { return variables.settingService.getSetting( "cb_media_provider" ); } @@ -67,7 +66,7 @@ component accessors="true" singleton { * * @return contentbox.models.media.BaseProvider */ - function getDefaultProvider(){ + function getDefaultProvider() { return getProvider( getDefaultProviderName() ); } @@ -78,7 +77,7 @@ component accessors="true" singleton { * * @return contentbox.models.media.BaseProvider */ - function getProvider( required name ){ + function getProvider( required name ) { return variables.providers[ arguments.name ]; } @@ -87,7 +86,9 @@ component accessors="true" singleton { * * @provider The provider object to register */ - MediaService function registerProvider( required contentbox.models.media.BaseProvider provider ){ + MediaService function registerProvider( + required contentbox.models.media.BaseProvider provider + ) { variables.providers[ arguments.provider.getName() ] = arguments.provider; return this; } @@ -97,7 +98,7 @@ component accessors="true" singleton { * * @name The name of the provider to unregister */ - MediaService function unRegisterProvider( required name ){ + MediaService function unRegisterProvider( required name ) { structDelete( variables.providers, arguments.name ); return this; } @@ -105,8 +106,10 @@ component accessors="true" singleton { /** * Get an array of registered providers in alphabetical order */ - array function getRegisteredProviders(){ - return listToArray( listSort( structKeyList( variables.providers ), "textnocase" ) ); + array function getRegisteredProviders() { + return listToArray( + listSort( structKeyList( variables.providers ), "textnocase" ) + ); } /** @@ -114,14 +117,16 @@ component accessors="true" singleton { * * @return array of structs { name, displayName, description } */ - array function getRegisteredProvidersMap(){ - return getRegisteredProviders().map( function( thisProvider ){ - return { - name : arguments.thisProvider, - displayName : variables.providers[ arguments.thisProvider ].getDisplayName(), - description : variables.providers[ arguments.thisProvider ].getDescription() - }; - } ); + array function getRegisteredProvidersMap() { + return getRegisteredProviders().map( + function( thisProvider ) { + return { + name : arguments.thisProvider, + displayName: variables.providers[ arguments.thisProvider ].getDisplayName(), + description: variables.providers[ arguments.thisProvider ].getDescription() + }; + } + ); } /** @@ -129,9 +134,9 @@ component accessors="true" singleton { * * @absolute Return the absolute path or relative, if absolute then it expands the path. */ - function getCoreMediaRoot( required boolean absolute = false ){ + function getCoreMediaRoot( required boolean absolute = false ) { var mRoot = variables.settingService.getSetting( "cb_media_directoryRoot", variables.DEFAULT_MEDIA_ROOT ); return ( arguments.absolute ? expandPath( mRoot ) : mRoot ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/media/RelocationMediaProvider.cfc b/modules/contentbox/models/media/RelocationMediaProvider.cfc index 0cbbd01402..cd3affc97e 100644 --- a/modules/contentbox/models/media/RelocationMediaProvider.cfc +++ b/modules/contentbox/models/media/RelocationMediaProvider.cfc @@ -5,13 +5,13 @@ * --- * Deliver file via pagecontext forward */ -component accessors="true" extends="BaseProvider" singleton { +component accessors="true" extends ="BaseProvider" singleton { /** * Constructor */ - any function init(){ - variables.name = "RelocationMediaProvider"; + any function init() { + variables.name = "RelocationMediaProvider"; variables.displayName = "Relocation Media Provider"; variables.description = "This provider will relocate to the real physical location in the server for the media path requested. Use only if the media root is web accessible, so double check your media root."; @@ -23,7 +23,7 @@ component accessors="true" extends="BaseProvider" singleton { * * @mediaPath.hint the media path to deliver back to the user */ - any function deliverMedia( required mediaPath ){ + any function deliverMedia( required mediaPath ) { location( url = getPublicURL( arguments.mediaPath ), addToken = false, @@ -31,4 +31,4 @@ component accessors="true" extends="BaseProvider" singleton { ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/menu/Menu.cfc b/modules/contentbox/models/menu/Menu.cfc index 15ab103407..869f7a57c0 100644 --- a/modules/contentbox/models/menu/Menu.cfc +++ b/modules/contentbox/models/menu/Menu.cfc @@ -13,121 +13,113 @@ component cachename ="cbMenu" cacheuse ="read-write" { - - /* ********************************************************************* - ** DI - ********************************************************************* */ + /********************************************************************** + * ** DI + **********************************************************************/ property - name ="menuService" - inject ="provider:menuService@contentbox" + name="menuService" + inject="provider:menuService@contentbox" persistent="false"; property - name ="menuItemService" - inject ="provider:menuItemService@contentbox" + name="menuItemService" + inject="provider:menuItemService@contentbox" persistent="false"; property - name ="ORMService" - inject ="provider:entityservice" + name="ORMService" + inject="provider:entityservice" persistent="false"; - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="menuID" - column ="menuID" + name="menuID" + column="menuID" fieldtype="id" generator="uuid" - length ="36" - ormtype ="string" - update ="false"; + length="36" + ormtype="string" + update="false"; property - name ="title" - column ="title" + name="title" + column="title" notnull="true" ormtype="string" - length ="200" + length="200" default="" - index ="idx_menutitle"; + index="idx_menutitle"; property - name ="slug" - column ="slug" + name="slug" + column="slug" notnull="true" ormtype="string" - length ="200" + length="200" default="" - index ="idx_menuslug"; + index="idx_menuslug"; property - name ="menuClass" - column ="menuClass" + name="menuClass" + column="menuClass" ormtype="string" - length ="160" + length="160" default=""; property - name ="listClass" - column ="listClass" + name="listClass" + column="listClass" ormtype="string" - length ="160" + length="160" default=""; property - name ="listType" - column ="listType" + name="listType" + column="listType" ormtype="string" - length ="20" + length="20" default="ul"; - /* ********************************************************************* - ** RELATIONSHIPS - ********************************************************************* */ + /********************************************************************** + * ** RELATIONSHIPS + **********************************************************************/ // M20 -> site loaded as a proxy and fetched immediately property - name ="site" - notnull ="true" - cfc ="contentbox.models.system.Site" + name="site" + notnull="true" + cfc="contentbox.models.system.Site" fieldtype="many-to-one" - fkcolumn ="FK_siteID" - lazy ="true"; + fkcolumn="FK_siteID" + lazy="true"; // O2M -> Comments property - name ="menuItems" + name="menuItems" singularName="menuItem" - fieldtype ="one-to-many" - type ="array" - cfc ="contentbox.models.menu.item.BaseMenuItem" - fkcolumn ="FK_menuID" - cascade ="all-delete-orphan" - inverse ="true" - lazy ="extra"; - - /* ********************************************************************* - ** PK + CONSTRAINTS - ********************************************************************* */ + fieldtype="one-to-many" + type="array" + cfc="contentbox.models.menu.item.BaseMenuItem" + fkcolumn="FK_menuID" + cascade="all-delete-orphan" + inverse="true" + lazy="extra"; + /********************************************************************** + * ** PK + CONSTRAINTS + **********************************************************************/ this.pk = "menuID"; this.memento = { - defaultIncludes : [ - "listClass", - "listType", - "menuClass", - "slug", - "title" - ], - defaultExcludes : [ "site", "menuItems" ], - profiles : { - export : { - defaultIncludes : [ + defaultIncludes: [ "listClass", "listType", "menuClass", "slug", "title"], + defaultExcludes: [ "site", "menuItems"], + profiles : { + export: { + defaultIncludes: [ "listClass", "listType", "menuClass", @@ -138,28 +130,28 @@ component "menuItems.parentSnapshot:parent", "siteSnapshot:site" ], - defaultExcludes : [] + defaultExcludes: [] } } }; this.constraints = { - "title" : { required : true, size : "1..200" }, - "slug" : { required : true, size : "1..200" }, - "menuClass" : { required : false, size : "1..160" }, - "listClass" : { required : false, size : "1..160" }, - "listType" : { required : false, size : "1..20" } + "title" : { required: true, size: "1..200" }, + "slug" : { required: true, size: "1..200" }, + "menuClass": { required: false, size: "1..160" }, + "listClass": { required: false, size: "1..160" }, + "listType" : { required: false, size: "1..20" } }; - /* ********************************************************************* - ** CONSTRUCTOR - ********************************************************************* */ + /********************************************************************** + * ** CONSTRUCTOR + **********************************************************************/ /** * constructor */ - Menu function init(){ - variables.listType = "ul"; + Menu function init() { + variables.listType = "ul"; variables.menuItems = []; super.init(); @@ -167,14 +159,14 @@ component return this; } - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ /** * @Override due to bi-directional relationships */ - Menu function addMenuItem( required menuItem ){ + Menu function addMenuItem( required menuItem ) { // add them to the local array arrayAppend( variables.menuItems, arguments.menuItem ); // set the bi-directional relation @@ -185,7 +177,7 @@ component /** * @Override due to bi-directional relationships */ - Menu function setMenuItems( required array menuItems ){ + Menu function setMenuItems( required array menuItems ) { if ( hasMenuItem() ) { // manual remove, so hibernate can clear the existing relationships variables.menuItems.clear(); @@ -202,7 +194,7 @@ component * * @rawData The raw data from which to create menu items */ - array function populateMenuItems( required array rawData ){ + array function populateMenuItems( required array rawData ) { variables.menuItems.clear(); return createMenuItems( arguments.rawData ); } @@ -210,42 +202,75 @@ component /** * Retrieves root menu items (only items with no parents) */ - array function getRootMenuItems(){ + array function getRootMenuItems() { if ( hasMenuItem() ) { - return getMenuItems().filter( function( thisItem ){ - return !arguments.thisItem.hasParent(); - } ); + return getMenuItems().filter( + function( thisItem ) { + return !arguments.thisItem.hasParent(); + } + ); } return []; } - /* ********************************************************************* - ** PRIVATE FUNCTIONS - ********************************************************************* */ + /** + * Shortcut to get the site name + */ + function getSiteName() { + return getSite().getName(); + } + + /** + * Shortcut to get the site slug + */ + function getSiteSlug() { + return getSite().getSlug(); + } + + /** + * Shortcut to get the site id + */ + function getSiteId() { + if ( hasSite() ) { + return getSite().getsiteID(); + } + return ""; + } + + /** + * Build a site snapshot + */ + struct function getSiteSnapshot() { + return ( hasSite() ? getSite().getInfoSnapshot() : {} ); + } + + /********************************************************************** + * ** PRIVATE FUNCTIONS + **********************************************************************/ /** * Recursive function to build menu items hierarchy from raw data * * @rawData The raw data definitions for the menu items */ - private array function createMenuItems( required array rawData ){ + private array function createMenuItems( required array rawData ) { var items = []; // loop over rawData and create items :) for ( var data in arguments.rawData ) { var provider = variables.menuItemService.getProvider( data.menuType ); - var entity = variables.ORMService.new( entityName = provider.getEntityName() ); - var newItem = variables.menuItemService.populate( - target = entity, - memento = data, - exclude = "menuItemId,children,parent" - ); + var entity = variables.ORMService.new( entityName = provider.getEntityName() ); + var newItem = variables.menuItemService.populate( + target = entity, + memento = data, + exclude = "menuItemId,children,parent" + ); // Link the item to this menu addMenuItem( newItem ); // populate the children if ( !isNull( data.children ) && arrayLen( data.children ) ) { var children = createMenuItems( data.children ); - var setter = []; + var setter = []; for ( var child in children ) { // Link the child to this parent child.setParent( newItem ); @@ -261,35 +286,4 @@ component return items; } - /** - * Shortcut to get the site name - */ - function getSiteName(){ - return getSite().getName(); - } - - /** - * Shortcut to get the site slug - */ - function getSiteSlug(){ - return getSite().getSlug(); - } - - /** - * Shortcut to get the site id - */ - function getSiteId(){ - if ( hasSite() ) { - return getSite().getsiteID(); - } - return ""; - } - - /** - * Build a site snapshot - */ - struct function getSiteSnapshot(){ - return ( hasSite() ? getSite().getInfoSnapshot() : {} ); - } - -} +} \ No newline at end of file diff --git a/modules/contentbox/models/menu/MenuItemService.cfc b/modules/contentbox/models/menu/MenuItemService.cfc index 59d259d679..7a4d0ab07a 100644 --- a/modules/contentbox/models/menu/MenuItemService.cfc +++ b/modules/contentbox/models/menu/MenuItemService.cfc @@ -1,33 +1,28 @@ /** -******************************************************************************** -ContentBox - A Modular Content Platform -Copyright 2012 by Luis Majano and Ortus Solutions, Corp -www.ortussolutions.com -******************************************************************************** -Apache License, Version 2.0 - -Copyright Since [2012] [Luis Majano and Ortus Solutions,Corp] - -Licensed under the Apache License, Version 2.0 (the "License" ); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -******************************************************************************** -* Service to handle menu items. -*/ -component - extends ="cborm.models.VirtualEntityService" - accessors="true" - singleton -{ - + * ******************************************************************************** + * ContentBox - A Modular Content Platform + * Copyright 2012 by Luis Majano and Ortus Solutions, Corp + * www.ortussolutions.com + * ******************************************************************************** + * Apache License, Version 2.0 + * + * Copyright Since [2012] [Luis Majano and Ortus Solutions,Corp] + * + * Licensed under the Apache License, Version 2.0 (the "License" ); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ******************************************************************************** + * Service to handle menu items. + */ +component extends ="cborm.models.VirtualEntityService" accessors="true" singleton { // DI property name="wirebox" inject="wirebox"; @@ -39,7 +34,7 @@ component /** * Constructor */ - MenuItemService function init(){ + MenuItemService function init() { // init it super.init( entityName = "cbMenuItem" ); variables.providers = {}; @@ -50,13 +45,31 @@ component /** * Runs after constructor to complete DI */ - function onDIComplete(){ - registerProvider( type = "URL", providerPath = "contentbox.models.menu.providers.URLProvider" ); - registerProvider( type = "Content", providerPath = "contentbox.models.menu.providers.ContentProvider" ); - registerProvider( type = "JS", providerPath = "contentbox.models.menu.providers.JSProvider" ); - registerProvider( type = "Media", providerPath = "contentbox.models.menu.providers.MediaProvider" ); - registerProvider( type = "SubMenu", providerPath = "contentbox.models.menu.providers.SubMenuProvider" ); - registerProvider( type = "Free", providerPath = "contentbox.models.menu.providers.FreeProvider" ); + function onDIComplete() { + registerProvider( + type = "URL", + providerPath = "contentbox.models.menu.providers.URLProvider" + ); + registerProvider( + type = "Content", + providerPath = "contentbox.models.menu.providers.ContentProvider" + ); + registerProvider( + type = "JS", + providerPath = "contentbox.models.menu.providers.JSProvider" + ); + registerProvider( + type = "Media", + providerPath = "contentbox.models.menu.providers.MediaProvider" + ); + registerProvider( + type = "SubMenu", + providerPath = "contentbox.models.menu.providers.SubMenuProvider" + ); + registerProvider( + type = "Free", + providerPath = "contentbox.models.menu.providers.FreeProvider" + ); } /** @@ -65,7 +78,10 @@ component * @type.hint The type of provider * @providerPath.hint Logical path for getting instance of provider */ - public MenuItemService function registerProvider( required string type, required string providerPath ){ + public MenuItemService function registerProvider( + required string type, + required string providerPath + ) { variables.providers[ arguments.type ] = wirebox.getInstance( arguments.providerPath ); return this; } @@ -75,7 +91,7 @@ component * * @type.hint The type of provider */ - public MenuItemService function unRegisterProvider( required string type ){ + public MenuItemService function unRegisterProvider( required string type ) { structDelete( variables.providers, arguments.type ); return this; } @@ -85,8 +101,8 @@ component * * @type.hint The type of provider */ - public any function getProvider( required string type ){ + public any function getProvider( required string type ) { return variables.providers[ arguments.type ]; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/menu/MenuService.cfc b/modules/contentbox/models/menu/MenuService.cfc index 985d03c7d1..6d060ee1ba 100644 --- a/modules/contentbox/models/menu/MenuService.cfc +++ b/modules/contentbox/models/menu/MenuService.cfc @@ -5,21 +5,18 @@ * --- * Service to handle menu operations. */ -component - extends ="cborm.models.VirtualEntityService" - accessors="true" - singleton -{ - +component extends ="cborm.models.VirtualEntityService" accessors="true" singleton { // DI property name="renderer" inject="coldbox:renderer"; + property name="menuItemService" inject="menuItemService@contentbox"; + property name="dateUtil" inject="DateUtil@contentbox"; /** * Constructor */ - MenuService function init(){ + MenuService function init() { // init it super.init( entityName = "cbMenu" ); return this; @@ -33,7 +30,7 @@ component * * @return The saved menu */ - function save( required menu, string originalSlug = "" ){ + function save( required menu, string originalSlug = "" ) { return super.save( arguments.menu ); } @@ -54,16 +51,16 @@ component boolean asQuery = false, string sortOrder = "title", string siteID = "" - ){ + ) { var results = {}; - var c = newCriteria(); + var c = newCriteria(); // Search if ( len( arguments.searchTerm ) ) { c.$or( - c.restrictions.like( "title", "%#arguments.searchTerm#%" ), - c.restrictions.like( "slug", "%#arguments.searchTerm#%" ) - ); + c.restrictions.like( "title", "%#arguments.searchTerm#%" ), + c.restrictions.like( "slug", "%#arguments.searchTerm#%" ) + ); } // Site Filter @@ -74,11 +71,11 @@ component // run criteria query and projections count results.count = c.count( "menuID" ); results.menus = c.list( - offset = arguments.offset, - max = arguments.max, - sortOrder = arguments.sortOrder, - asQuery = arguments.asQuery - ); + offset = arguments.offset, + max = arguments.max, + sortOrder = arguments.sortOrder, + asQuery = arguments.asQuery + ); return results; } @@ -91,16 +88,19 @@ component * * @return The menu found or a new menu blank */ - function findBySlug( required any slug, string siteID = "" ){ + function findBySlug( required any slug, string siteID = "" ) { // By criteria now var menu = newCriteria() .isEq( "slug", arguments.slug ) - .when( len( arguments.siteID ), function( c ){ - c.isEq( "site.siteID", siteID ); - } ) + .when( + len( arguments.siteID ), + function( c ) { + c.isEq( "site.siteID", siteID ); + } + ) .get(); // return accordingly - return ( isNull( menu ) ? new () : menu ); + return ( isNull( menu ) ? new() : menu ); } /** @@ -108,10 +108,12 @@ component * * @site The site to export from */ - array function getAllForExport( required site ){ - return findAllWhere( { site : arguments.site } ).map( function( thisItem ){ - return thisItem.getMemento( profile: "export" ); - } ); + array function getAllForExport( required site ) { + return findAllWhere( { site: arguments.site } ).map( + function( thisItem ) { + return thisItem.getMemento( profile = "export" ); + } + ); } /** @@ -119,11 +121,14 @@ component * * @siteID Filter by site */ - array function getAllSlugs( string siteID = "" ){ + array function getAllSlugs( string siteID = "" ) { return newCriteria() - .when( len( arguments.siteID ), function( c ){ - c.isEq( "site.siteID", siteID ); - } ) + .when( + len( arguments.siteID ), + function( c ) { + c.isEq( "site.siteID", siteID ); + } + ) .withProjections( property = "slug" ) .list( sortOrder = "slug asc" ); } @@ -138,14 +143,17 @@ component * * @throws InvalidImportFormat */ - string function importFromFile( required importFile, boolean override = false ){ - var data = fileRead( arguments.importFile ); + string function importFromFile( required importFile, boolean override = false ) { + var data = fileRead( arguments.importFile ); var importLog = createObject( "java", "java.lang.StringBuilder" ).init( - "Starting import with override = #arguments.override#...
" - ); + "Starting import with override = #arguments.override#...
" + ); if ( !isJSON( data ) ) { - throw( message = "Cannot import file as the contents is not JSON", type = "InvalidImportFormat" ); + throw( + message = "Cannot import file as the contents is not JSON", + type = "InvalidImportFormat" + ); } // deserialize packet: Should be array of { settingID, name, value } return importFromData( @@ -170,16 +178,16 @@ component boolean override = false, required importLog, site - ){ + ) { var siteService = getWireBox().getInstance( "siteService@contentbox" ); // if struct, inflate into an array if ( isStruct( arguments.importData ) ) { - arguments.importData = [ arguments.importData ]; + arguments.importData = [ arguments.importData]; } // Setup logging function - var logThis = function( message ){ + var logThis = function( message ) { variables.logger.info( arguments.message ); importLog.append( arguments.message & "
" ); }; @@ -189,14 +197,18 @@ component for ( var thisMenu in arguments.importData ) { // Determine Site if not passed from import data if ( isNull( arguments.site ) ) { - logThis( "+ Site not sent via arguments, inflating from menu data (#thisMenu.site.slug#)" ); + logThis( + "+ Site not sent via arguments, inflating from menu data (#thisMenu.site.slug#)" + ); arguments.site = siteService.getBySlugOrFail( thisMenu.site.slug ); } - logThis( "+ Importing menu (#thisMenu.slug#) to site (#arguments.site.getSlug()#)" ); + logThis( + "+ Importing menu (#thisMenu.slug#) to site (#arguments.site.getSlug()#)" + ); // Get new or persisted from site by slug - var oMenu = findWhere( { "slug" : thisMenu.slug, "site" : arguments.site } ); + var oMenu = findWhere( { "slug": thisMenu.slug, "site": arguments.site } ); if ( isNull( oMenu ) ) { logThis( "+ New menu (#thisMenu.slug#) to import" ); oMenu = this.new(); @@ -218,11 +230,11 @@ component // populate content from data getBeanPopulator().populateFromStruct( - target = oMenu, - memento = thisMenu, - composeRelationships = false, - exclude = "menuID,menuItems,site" - ); + target = oMenu, + memento = thisMenu, + composeRelationships = false, + exclude = "menuID,menuItems,site" + ); // Compose Menu Items if ( arrayLen( thisMenu.menuItems ) ) { @@ -230,13 +242,17 @@ component } entitySave( oMenu ); - logThis( "+ Imported menu (#thisMenu.slug#) to site (#arguments.site.getSlug()#)" ); + logThis( + "+ Imported menu (#thisMenu.slug#) to site (#arguments.site.getSlug()#)" + ); } // end import loop // Save them? if ( !arrayLen( arguments.importData ) ) { - logThis( "No menus imported as none where found or able to be overriden from the import file." ); + logThis( + "No menus imported as none where found or able to be overriden from the import file." + ); } } // end for transaction @@ -251,15 +267,15 @@ component * @menuString build-up string for menu content * @inChild flag for whether the content item is being evaluated as itself, or as a child of another item */ - public String function buildEditableMenu( + public string function buildEditableMenu( required array menu, required string menuString = "", boolean inChild = false - ){ + ) { // loop over menu items for ( var item in arguments.menu ) { var providerContent = ""; - var skipItem = false; + var skipItem = false; // if item has a parent, and it's being evaluated on the same level as its parent, skip it if ( item.hasParent() && !inChild ) { @@ -271,16 +287,16 @@ component arguments.menuString &= "
  • "; // render default menu item - var args = { menuItem : item, provider : item.getProvider() }; + var args = { menuItem: item, provider: item.getProvider() }; savecontent variable="providerContent" { writeOutput( variables.renderer.view( - view = "menus/provider", - module = "contentbox-admin", - args = args - ) + view = "menus/provider", + module = "contentbox-admin", + args = args + ) ); - }; + } menuString &= providerContent; // if this item has children, recursively call this method to build them out too @@ -308,16 +324,25 @@ component required any slug, any menuID = "", string siteID = "" - ){ + ) { return newCriteria() - .isEq( "slug", arguments.slug ) - .when( len( arguments.siteID ), function( c ){ - c.isEq( "site.siteID", siteID ); - } ) - .when( len( arguments.menuID ), function( c ){ - c.ne( "menuID", menuID ); - } ) - .count() > 0 ? false : true; + .isEq( "slug", arguments.slug ) + .when( + len( arguments.siteID ), + function( c ) { + c.isEq( "site.siteID", siteID ); + } + ) + .when( + len( arguments.menuID ), + function( c ) { + c.ne( "menuID", menuID ); + } + ) + .count() > + 0 + ? false + : true; } /** @@ -325,8 +350,8 @@ component * * @slug The slug to make unique */ - private function getUniqueSlugHash( required string slug ){ + private function getUniqueSlugHash( required string slug ) { return "#arguments.slug#-#lCase( left( hash( now() ), 5 ) )#"; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/menu/item/BaseMenuItem.cfc b/modules/contentbox/models/menu/item/BaseMenuItem.cfc index 2efadf16a0..cf7be57a48 100644 --- a/modules/contentbox/models/menu/item/BaseMenuItem.cfc +++ b/modules/contentbox/models/menu/item/BaseMenuItem.cfc @@ -14,139 +14,133 @@ component cacheuse ="read-write" discriminatorColumn="menuType" { - - /* ********************************************************************* - ** DI - ********************************************************************* */ + /********************************************************************** + * ** DI + **********************************************************************/ property - name ="menuItemService" - inject ="provider:menuItemService@contentbox" + name="menuItemService" + inject="provider:menuItemService@contentbox" persistent="false"; - /* ********************************************************************* - ** PROPERTIES due to ACF Bug - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES due to ACF Bug + **********************************************************************/ property - name ="createdDate" - column ="createdDate" - type ="date" + name="createdDate" + column="createdDate" + type="date" ormtype="timestamp" notnull="true" - update ="false"; + update="false"; property - name ="modifiedDate" - column ="modifiedDate" - type ="date" + name="modifiedDate" + column="modifiedDate" + type="date" ormtype="timestamp" notnull="true"; property - name ="isDeleted" - column ="isDeleted" + name="isDeleted" + column="isDeleted" ormtype="boolean" notnull="true" default="false"; - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="menuItemID" - column ="menuItemID" + name="menuItemID" + column="menuItemID" fieldtype="id" generator="uuid" - length ="36" - ormtype ="string" - update ="false"; + length="36" + ormtype="string" + update="false"; property - name ="title" - column ="title" + name="title" + column="title" notnull="true" ormtype="string" - length ="200" + length="200" default=""; property - name ="label" - column ="label" + name="label" + column="label" notnull="false" ormtype="string" - length ="200" + length="200" default=""; property - name ="itemClass" - column ="itemClass" + name="itemClass" + column="itemClass" notnull="false" ormtype="string" - length ="200" + length="200" default=""; property - name ="data" - column ="data" + name="data" + column="data" notnull="false" ormtype="string" default=""; - property - name ="active" - column ="active" - ormtype="boolean" - default="true"; + property name="active" column="active" ormtype="boolean" default="true"; property - name ="menuType" + name="menuType" column="menuType" insert="false" update="false"; - /* ********************************************************************* - ** RELATIONSHIPS - ********************************************************************* */ + /********************************************************************** + * ** RELATIONSHIPS + **********************************************************************/ // M20 - Owning menu property - name ="menu" - cfc ="contentbox.models.menu.Menu" + name="menu" + cfc="contentbox.models.menu.Menu" fieldtype="many-to-one" - fkcolumn ="FK_menuID" - lazy ="true" - notnull ="true"; + fkcolumn="FK_menuID" + lazy="true" + notnull="true"; // M20 - Parent Menu item property - name ="parent" - cfc ="BaseMenuItem" + name="parent" + cfc="BaseMenuItem" fieldtype="many-to-one" - fkcolumn ="FK_parentID" - lazy ="true"; + fkcolumn="FK_parentID" + lazy="true"; // O2M - Child Menu Item property - name ="children" + name="children" singularName="child" - fieldtype ="one-to-many" - type ="array" - lazy ="extra" - cfc ="BaseMenuItem" - fkcolumn ="FK_parentID" - inverse ="true" - cascade ="all-delete-orphan"; - - /* ********************************************************************* - ** PK + CONSTRAINTS - ********************************************************************* */ + fieldtype="one-to-many" + type="array" + lazy="extra" + cfc="BaseMenuItem" + fkcolumn="FK_parentID" + inverse="true" + cascade="all-delete-orphan"; + /********************************************************************** + * ** PK + CONSTRAINTS + **********************************************************************/ this.pk = "menuItemID"; this.memento = { - defaultIncludes : [ + defaultIncludes: [ "active", "data", "itemClass", @@ -155,22 +149,22 @@ component "children", "parentSnapshot:parent" ], - defaultExcludes : [ "menu", "parent" ] + defaultExcludes: [ "menu", "parent"] }; this.constraints = { - "title" : { required : true, size : "1..200" }, - "label" : { required : false, size : "1..200" }, - "itemClass" : { required : false, size : "1..200" }, - "data" : { required : false, size : "1..255" } + "title" : { required: true, size: "1..200" }, + "label" : { required: false, size: "1..200" }, + "itemClass": { required: false, size: "1..200" }, + "data" : { required: false, size: "1..255" } }; - /* ********************************************************************* - ** CONSTRUCTOR - ********************************************************************* */ + /********************************************************************** + * ** CONSTRUCTOR + **********************************************************************/ - BaseMenuItem function init(){ - variables.active = true; + BaseMenuItem function init() { + variables.active = true; variables.children = []; super.init(); @@ -181,37 +175,37 @@ component /** * Build a parent snapshot */ - struct function getParentSnapshot(){ + struct function getParentSnapshot() { return ( hasParent() ? getParent().getInfoSnapshot() : {} ); } /** * Utility method to get a snapshot of this menu item */ - struct function getInfoSnapshot(){ + struct function getInfoSnapshot() { if ( isLoaded() ) { return { - "menuItemID" : getId(), - "title" : getTitle(), - "active" : getActive(), - "menuType" : getMenuType() + "menuItemID": getId(), + "title" : getTitle(), + "active" : getActive(), + "menuType" : getMenuType() }; } return {}; } - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ /** * Get a handy, formatted string of attributes that are applicable for the current menu item */ - public string function getAttributesAsString(){ - var str = ""; + public string function getAttributesAsString() { + var str = ""; var title = !isNull( getTitle() ) ? getTitle() : ""; - var cls = !isNull( getItemClass() ) ? getItemClass() : ""; - var data = !isNull( getData() ) ? getData() : ""; + var cls = !isNull( getItemClass() ) ? getItemClass() : ""; + var data = !isNull( getData() ) ? getData() : ""; // handle title if ( len( title ) ) { str &= " title=""#htmlEditFormat( title )#"""; @@ -255,8 +249,8 @@ component * * @options.hint Additional arguments to be used in the method */ - public boolean function canDisplay( required struct options = {} ){ + public boolean function canDisplay( required struct options = {} ) { return getActive(); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/menu/item/ContentMenuItem.cfc b/modules/contentbox/models/menu/item/ContentMenuItem.cfc index 7c8c69bddb..2aaf203258 100644 --- a/modules/contentbox/models/menu/item/ContentMenuItem.cfc +++ b/modules/contentbox/models/menu/item/ContentMenuItem.cfc @@ -12,61 +12,60 @@ component extends ="contentbox.models.menu.item.BaseMenuItem" discriminatorValue="Content" { - - /* ********************************************************************* - ** DI - ********************************************************************* */ + /********************************************************************** + * ** DI + **********************************************************************/ property - name ="provider" + name="provider" persistent="false" - inject ="provider:contentbox.models.menu.providers.ContentProvider"; + inject="provider:contentbox.models.menu.providers.ContentProvider"; + property - name ="contentService" + name="contentService" persistent="false" - inject ="provider:contentService@contentbox"; + inject="provider:contentService@contentbox"; - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="contentSlug" - column ="contentSlug" + name="contentSlug" + column="contentSlug" notnull="false" ormtype="string" default=""; property - name ="target" - column ="target" + name="target" + column="target" notnull="false" ormtype="string" default=""; property - name ="urlClass" - column ="urlClass" + name="urlClass" + column="urlClass" notnull="false" ormtype="string" default=""; + /********************************************************************** + * ** PK + CONSTRAINTS + **********************************************************************/ - /* ********************************************************************* - ** PK + CONSTRAINTS - ********************************************************************* */ - - this.constraints[ "contentSlug" ] = { required : false, size : "1..255" }; - this.constraints[ "target" ] = { required : false, size : "1..255" }; - this.constraints[ "urlClass" ] = { required : false, size : "1..255" }; + this.constraints[ "contentSlug" ] = { required: false, size: "1..255" }; + this.constraints[ "target" ] = { required: false, size: "1..255" }; + this.constraints[ "urlClass" ] = { required: false, size: "1..255" }; - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ - function init(){ + function init() { super.init(); - appendToMemento( [ "contentSlug", "target", "urlClass" ], "defaultIncludes" ); + appendToMemento( [ "contentSlug", "target", "urlClass"], "defaultIncludes" ); return this; } @@ -76,14 +75,14 @@ component * * @options.hint Additional arguments to be used in the method */ - public boolean function canDisplay( required struct options = {} ){ + public boolean function canDisplay( required struct options = {} ) { var display = super.canDisplay( argumentCollection = arguments ); if ( display ) { var content = contentService.findBySlug( slug = getContentSlug(), siteID = getMenu().getSiteID() ); - var type = content.getContentType(); + var type = content.getContentType(); return content.isLoaded() && ( type == "Page" || type == "Entry" ) ? true : false; } return display; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/menu/item/FreeMenuItem.cfc b/modules/contentbox/models/menu/item/FreeMenuItem.cfc index b2a125857f..72dd4548b9 100644 --- a/modules/contentbox/models/menu/item/FreeMenuItem.cfc +++ b/modules/contentbox/models/menu/item/FreeMenuItem.cfc @@ -12,22 +12,21 @@ component extends ="contentbox.models.menu.item.BaseMenuItem" discriminatorValue="Free" { - - /* ********************************************************************* - ** DI - ********************************************************************* */ + /********************************************************************** + * ** DI + **********************************************************************/ property - name ="provider" + name="provider" persistent="false" - inject ="provider:contentbox.models.menu.providers.FreeProvider"; + inject="provider:contentbox.models.menu.providers.FreeProvider"; - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ -} + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ +} \ No newline at end of file diff --git a/modules/contentbox/models/menu/item/JSMenuItem.cfc b/modules/contentbox/models/menu/item/JSMenuItem.cfc index 06fce7b3e4..1732c276d7 100644 --- a/modules/contentbox/models/menu/item/JSMenuItem.cfc +++ b/modules/contentbox/models/menu/item/JSMenuItem.cfc @@ -12,51 +12,49 @@ component extends ="contentbox.models.menu.item.BaseMenuItem" discriminatorValue="JS" { - - /* ********************************************************************* - ** DI - ********************************************************************* */ + /********************************************************************** + * ** DI + **********************************************************************/ property - name ="provider" + name="provider" persistent="false" - inject ="provider:contentbox.models.menu.providers.JSProvider"; + inject="provider:contentbox.models.menu.providers.JSProvider"; - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="js" - column ="js" + name="js" + column="js" notnull="false" ormtype="string" default=""; property - name ="urlClass" - column ="urlClass" + name="urlClass" + column="urlClass" notnull="false" ormtype="string" default=""; + /********************************************************************** + * ** PK + CONSTRAINTS + **********************************************************************/ - /* ********************************************************************* - ** PK + CONSTRAINTS - ********************************************************************* */ - - this.constraints[ "js" ] = { required : false, size : "1..255" }; - this.constraints[ "urlClass" ] = { required : false, size : "1..255" }; + this.constraints[ "js" ] = { required: false, size: "1..255" }; + this.constraints[ "urlClass" ] = { required: false, size: "1..255" }; - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ - function init(){ + function init() { super.init(); - appendToMemento( [ "js", "urlClass" ], "defaultIncludes" ); + appendToMemento( [ "js", "urlClass"], "defaultIncludes" ); return this; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/menu/item/MediaMenuItem.cfc b/modules/contentbox/models/menu/item/MediaMenuItem.cfc index 4bdba3c40b..2958ba13ec 100644 --- a/modules/contentbox/models/menu/item/MediaMenuItem.cfc +++ b/modules/contentbox/models/menu/item/MediaMenuItem.cfc @@ -12,58 +12,56 @@ component extends ="contentbox.models.menu.item.BaseMenuItem" discriminatorValue="Media" { - - /* ********************************************************************* - ** DI - ********************************************************************* */ + /********************************************************************** + * ** DI + **********************************************************************/ property - name ="provider" + name="provider" persistent="false" - inject ="provider:contentbox.models.menu.providers.MediaProvider"; + inject="provider:contentbox.models.menu.providers.MediaProvider"; - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="mediaPath" - column ="mediaPath" + name="mediaPath" + column="mediaPath" notnull="false" ormtype="string" default=""; property - name ="target" - column ="target" + name="target" + column="target" notnull="false" ormtype="string" default=""; property - name ="urlClass" - column ="urlClass" + name="urlClass" + column="urlClass" notnull="false" ormtype="string" default=""; + /********************************************************************** + * ** PK + CONSTRAINTS + **********************************************************************/ - /* ********************************************************************* - ** PK + CONSTRAINTS - ********************************************************************* */ - - this.constraints[ "mediaPath" ] = { required : false, size : "1..255" }; - this.constraints[ "target" ] = { required : false, size : "1..255" }; - this.constraints[ "urlClass" ] = { required : false, size : "1..255" }; + this.constraints[ "mediaPath" ] = { required: false, size: "1..255" }; + this.constraints[ "target" ] = { required: false, size: "1..255" }; + this.constraints[ "urlClass" ] = { required: false, size: "1..255" }; - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ - function init(){ + function init() { super.init(); - appendToMemento( [ "mediaPath", "target", "urlClass" ], "defaultIncludes" ); + appendToMemento( [ "mediaPath", "target", "urlClass"], "defaultIncludes" ); return this; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/menu/item/SubMenuItem.cfc b/modules/contentbox/models/menu/item/SubMenuItem.cfc index 58048f52b7..a712777ee3 100644 --- a/modules/contentbox/models/menu/item/SubMenuItem.cfc +++ b/modules/contentbox/models/menu/item/SubMenuItem.cfc @@ -12,40 +12,38 @@ component extends ="contentbox.models.menu.item.BaseMenuItem" discriminatorValue="SubMenu" { - - /* ********************************************************************* - ** DI - ********************************************************************* */ + /********************************************************************** + * ** DI + **********************************************************************/ property - name ="provider" + name="provider" persistent="false" - inject ="provider:contentbox.models.menu.providers.SubMenuProvider"; + inject="provider:contentbox.models.menu.providers.SubMenuProvider"; - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="menuSlug" - column ="menuSlug" + name="menuSlug" + column="menuSlug" notnull="false" ormtype="string" default=""; + /********************************************************************** + * ** PK + CONSTRAINTS + **********************************************************************/ - /* ********************************************************************* - ** PK + CONSTRAINTS - ********************************************************************* */ - - this.constraints[ "menuSlug" ] = { required : false, size : "1..255" }; + this.constraints[ "menuSlug" ] = { required: false, size: "1..255" }; - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ - function init(){ + function init() { super.init(); - appendToMemento( [ "menuSlug" ], "defaultIncludes" ); + appendToMemento( [ "menuSlug"], "defaultIncludes" ); return this; } @@ -55,7 +53,7 @@ component * * @options.hint Additional arguments to be used in the method */ - public boolean function canDisplay( required struct options = {} ){ + public boolean function canDisplay( required struct options = {} ) { var display = super.canDisplay( argumentCollection = arguments ); if ( display ) { var slug = getMenuSlug(); @@ -64,4 +62,4 @@ component return display; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/menu/item/URLMenuItem.cfc b/modules/contentbox/models/menu/item/URLMenuItem.cfc index 52db84f625..a0c2762a95 100644 --- a/modules/contentbox/models/menu/item/URLMenuItem.cfc +++ b/modules/contentbox/models/menu/item/URLMenuItem.cfc @@ -12,59 +12,57 @@ component extends ="contentbox.models.menu.item.BaseMenuItem" discriminatorValue="URL" { - - /* ********************************************************************* - ** DI - ********************************************************************* */ + /********************************************************************** + * ** DI + **********************************************************************/ property - name ="provider" + name="provider" persistent="false" - inject ="provider:contentbox.models.menu.providers.URLProvider"; + inject="provider:contentbox.models.menu.providers.URLProvider"; - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="url" - column ="url" + name="url" + column="url" notnull="false" ormtype="string" default=""; property - name ="target" - column ="target" + name="target" + column="target" notnull="false" ormtype="string" default=""; property - name ="urlClass" - column ="urlClass" + name="urlClass" + column="urlClass" notnull="false" ormtype="string" default=""; + /********************************************************************** + * ** PK + CONSTRAINTS + **********************************************************************/ - /* ********************************************************************* - ** PK + CONSTRAINTS - ********************************************************************* */ - - this.constraints[ "url" ] = { required : false, size : "1..255" }; - this.constraints[ "target" ] = { required : false, size : "1..255" }; - this.constraints[ "urlClass" ] = { required : false, size : "1..255" }; + this.constraints[ "url" ] = { required: false, size: "1..255" }; + this.constraints[ "target" ] = { required: false, size: "1..255" }; + this.constraints[ "urlClass" ] = { required: false, size: "1..255" }; - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ - function init(){ + function init() { super.init(); - appendToMemento( [ "target", "url", "urlClass" ], "defaultIncludes" ); + appendToMemento( [ "target", "url", "urlClass"], "defaultIncludes" ); return this; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/menu/providers/BaseProvider.cfc b/modules/contentbox/models/menu/providers/BaseProvider.cfc index 16f1596f05..73d05bc106 100644 --- a/modules/contentbox/models/menu/providers/BaseProvider.cfc +++ b/modules/contentbox/models/menu/providers/BaseProvider.cfc @@ -6,16 +6,15 @@ * Base Provider */ component accessors="true" { - - /* ********************************************************************* - ** DI - ********************************************************************* */ + /********************************************************************** + * ** DI + **********************************************************************/ property name="renderer" inject="coldbox:renderer"; - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property name="name" type="string"; @@ -27,43 +26,43 @@ component accessors="true" { property name="description" type="string"; - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ /** * Gets the name of the menu item provider */ - public string function getName(){ + public string function getName() { return name; } /** * Gets the entityName for the menu item provider */ - public string function getEntityName(){ + public string function getEntityName() { return entityName; } /** * Gets the name of the menu item provider */ - public string function getType(){ + public string function getType() { return type; } /** * Gets the iconCls of the menu item provider */ - public string function getIconClass(){ + public string function getIconClass() { return iconClass; } /** * Gets the description of the menu item provider */ - public string function getDescription(){ + public string function getDescription() { return description; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/menu/providers/ContentProvider.cfc b/modules/contentbox/models/menu/providers/ContentProvider.cfc index 6a7fa81310..032329de65 100644 --- a/modules/contentbox/models/menu/providers/ContentProvider.cfc +++ b/modules/contentbox/models/menu/providers/ContentProvider.cfc @@ -8,25 +8,26 @@ component implements="contentbox.models.menu.providers.IMenuItemProvider" extends ="contentbox.models.menu.providers.BaseProvider" - accessors =true + accessors ="#true#" { - - /* ********************************************************************* - ** DI - ********************************************************************* */ + /********************************************************************** + * ** DI + **********************************************************************/ property name="contentService" inject="id:contentService@contentbox"; + property name="CBHelper" inject="id:CBHelper@contentbox"; + property name="requestService" inject="coldbox:requestService"; - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ /** * Constructor */ - public ContentProvider function init(){ + public ContentProvider function init() { setName( "Content" ); setType( "Content" ); setIconClass( "fa fa-archive" ); @@ -41,33 +42,37 @@ component * @menuItem The menu item object * @options Additional arguments to be used in the method */ - string function getAdminTemplate( required any menuItem, required struct options = {} ){ - var prc = requestService.getContext().getPrivateCollection(); + string function getAdminTemplate( + required any menuItem, + required struct options = {} + ) { + var prc = requestService.getContext().getPrivateCollection(); var title = ""; - var slug = ""; + var slug = ""; prc.xehRelatedContentSelector = "#prc.cbAdminEntryPoint#.content.relatedContentSelector"; if ( !isNull( arguments.menuItem.getContentSlug() ) ) { - var content = contentService.findBySlug( - slug = arguments.menuItem.getContentSlug(), - siteID = arguments.menuItem.getMenu().getSiteID() - ); + var content = contentService.findBySlug( slug = arguments.menuItem.getContentSlug(), + siteID = arguments + .menuItem + .getMenu() + .getSiteID() ); if ( !isNull( content ) ) { title = content.getTitle(); - slug = arguments.menuItem.getContentSlug(); + slug = arguments.menuItem.getContentSlug(); } } return variables.renderer.view( - view = "menus/providers/content/admin", - module = "contentbox-admin", - args = { - menuItem : arguments.menuItem, - xehContentSelector : "#prc.cbAdminEntryPoint#.content.showRelatedContentSelector", - title : title, - slug : slug - } - ); + view = "menus/providers/content/admin", + module = "contentbox-admin", + args = { + menuItem : arguments.menuItem, + xehContentSelector: "#prc.cbAdminEntryPoint#.content.showRelatedContentSelector", + title : title, + slug : slug + } + ); } /** @@ -76,21 +81,25 @@ component * @menuItem The menu item object * @options Additional arguments to be used in the method */ - string function getDisplayTemplate( required any menuItem, required struct options = {} ){ - var content = variables.contentService.findBySlug( - slug = arguments.menuItem.getContentSlug(), - siteID = arguments.menuItem.getMenu().getSiteID() - ); + string function getDisplayTemplate( + required any menuItem, + required struct options = {} + ) { + var content = variables.contentService.findBySlug( slug = arguments.menuItem.getContentSlug(), + siteID = arguments + .menuItem + .getMenu() + .getSiteID() ); return variables.renderer.externalView( - view = "/contentbox/models/menu/views/content/display", - module = "contentbox", - args = { - menuItem : arguments.menuItem, - contentLink : variables.CBHelper.linkContent( content: content ), - data : arguments.menuItem.getMemento() - } - ); + view = "/contentbox/models/menu/views/content/display", + module = "contentbox", + args = { + menuItem : arguments.menuItem, + contentLink: variables.CBHelper.linkContent( content = content ), + data : arguments.menuItem.getMemento() + } + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/menu/providers/FreeProvider.cfc b/modules/contentbox/models/menu/providers/FreeProvider.cfc index 12ee6c77f7..c5bb2909b9 100644 --- a/modules/contentbox/models/menu/providers/FreeProvider.cfc +++ b/modules/contentbox/models/menu/providers/FreeProvider.cfc @@ -8,17 +8,17 @@ component implements="contentbox.models.menu.providers.IMenuItemProvider" extends ="contentbox.models.menu.providers.BaseProvider" - accessors =true + accessors ="#true#" { - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ /** * Constructor */ - public FreeProvider function init(){ + public FreeProvider function init() { setName( "Free" ); setType( "Free" ); setIconClass( "fa fa-eye" ); @@ -33,7 +33,10 @@ component * @menuItem.hint The menu item object * @options.hint Additional arguments to be used in the method */ - public string function getAdminTemplate( required any menuItem, required struct options = {} ){ + public string function getAdminTemplate( + required any menuItem, + required struct options = {} + ) { return ""; } @@ -43,16 +46,19 @@ component * @menuItem.hint The menu item object * @options.hint Additional arguments to be used in the method */ - public string function getDisplayTemplate( required any menuItem, required struct options = {} ){ + public string function getDisplayTemplate( + required any menuItem, + required struct options = {} + ) { var viewArgs = { - menuItem : arguments.menuItem, - data : arguments.menuItem.getMemento() + menuItem: arguments.menuItem, + data : arguments.menuItem.getMemento() }; return variables.renderer.externalView( - view = "/contentbox/models/menu/views/free/display", - module = "contentbox", - args = viewArgs - ); + view = "/contentbox/models/menu/views/free/display", + module = "contentbox", + args = viewArgs + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/menu/providers/IMenuItemProvider.cfc b/modules/contentbox/models/menu/providers/IMenuItemProvider.cfc index da81733144..43b9156aad 100644 --- a/modules/contentbox/models/menu/providers/IMenuItemProvider.cfc +++ b/modules/contentbox/models/menu/providers/IMenuItemProvider.cfc @@ -18,5 +18,4 @@ interface { public string function getAdminTemplate( required any menuItem, required struct options ); public string function getDisplayTemplate( required any menuItem, required struct options ); - -} +} \ No newline at end of file diff --git a/modules/contentbox/models/menu/providers/JSProvider.cfc b/modules/contentbox/models/menu/providers/JSProvider.cfc index 484949b1d6..007f1b3d9c 100644 --- a/modules/contentbox/models/menu/providers/JSProvider.cfc +++ b/modules/contentbox/models/menu/providers/JSProvider.cfc @@ -8,17 +8,17 @@ component implements="contentbox.models.menu.providers.IMenuItemProvider" extends ="contentbox.models.menu.providers.BaseProvider" - accessors =true + accessors ="#true#" { - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ /** * Constructor */ - public JSProvider function init(){ + public JSProvider function init() { setName( "JS" ); setType( "JS" ); setIconClass( "fa fa-code" ); @@ -26,19 +26,23 @@ component setDescription( "A menu item which executes JavaScript code" ); return this; } + /** * Retrieves template for use in admin screens for this type of menu item provider * * @menuItem.hint The menu item object * @options.hint Additional arguments to be used in the method */ - public string function getAdminTemplate( required any menuItem, required struct options = {} ){ - var viewArgs = { menuItem : arguments.menuItem }; + public string function getAdminTemplate( + required any menuItem, + required struct options = {} + ) { + var viewArgs = { menuItem: arguments.menuItem }; return variables.renderer.view( - view = "menus/providers/js/admin", - module = "contentbox-admin", - args = viewArgs - ); + view = "menus/providers/js/admin", + module = "contentbox-admin", + args = viewArgs + ); } /** @@ -47,13 +51,16 @@ component * @menuItem.hint The menu item object * @options.hint Additional arguments to be used in the method */ - public string function getDisplayTemplate( required any menuItem, required struct options = {} ){ - var viewArgs = { menuItem : arguments.menuItem }; + public string function getDisplayTemplate( + required any menuItem, + required struct options = {} + ) { + var viewArgs = { menuItem: arguments.menuItem }; return variables.renderer.externalView( - view = "/contentbox/models/menu/views/js/display", - module = "contentbox", - args = viewArgs - ); + view = "/contentbox/models/menu/views/js/display", + module = "contentbox", + args = viewArgs + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/menu/providers/MediaProvider.cfc b/modules/contentbox/models/menu/providers/MediaProvider.cfc index 6c4d4ac035..022df03f16 100644 --- a/modules/contentbox/models/menu/providers/MediaProvider.cfc +++ b/modules/contentbox/models/menu/providers/MediaProvider.cfc @@ -8,23 +8,22 @@ component implements="contentbox.models.menu.providers.IMenuItemProvider" extends ="contentbox.models.menu.providers.BaseProvider" - accessors =true + accessors ="#true#" { - - /* ********************************************************************* - ** DI - ********************************************************************* */ + /********************************************************************** + * ** DI + **********************************************************************/ property name="requestService" inject="coldbox:requestService"; - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ /** * Constructor */ - public MediaProvider function init(){ + public MediaProvider function init() { setName( "Media" ); setType( "Media" ); setIconClass( "fas fa-photo-video" ); @@ -32,36 +31,44 @@ component setDescription( "A menu item to a media item" ); return this; } + /** * Retrieves template for use in admin screens for this type of menu item provider * * @menuItem.hint The menu item object * @options.hint Additional arguments to be used in the method */ - public string function getAdminTemplate( required any menuItem, required struct options = {} ){ + public string function getAdminTemplate( + required any menuItem, + required struct options = {} + ) { var viewArgs = { - menuItem : arguments.menuItem, - xehMediaSelector : "#requestService.getContext().buildLink( to = "cbadmin.menus.filebrowser" )#" + menuItem : arguments.menuItem, + xehMediaSelector: "#requestService.getContext().buildLink( to = "cbadmin.menus.filebrowser" )#" }; return variables.renderer.view( - view = "menus/providers/media/admin", - module = "contentbox-admin", - args = viewArgs - ); + view = "menus/providers/media/admin", + module = "contentbox-admin", + args = viewArgs + ); } + /** * Retrieves template for use in rendering menu item on the site * * @menuItem.hint The menu item object * @options.hint Additional arguments to be used in the method */ - public string function getDisplayTemplate( required any menuItem, required struct options = {} ){ - var viewArgs = { menuItem : arguments.menuItem }; + public string function getDisplayTemplate( + required any menuItem, + required struct options = {} + ) { + var viewArgs = { menuItem: arguments.menuItem }; return variables.renderer.externalView( - view = "/contentbox/models/menu/views/media/display", - module = "contentbox", - args = viewArgs - ); + view = "/contentbox/models/menu/views/media/display", + module = "contentbox", + args = viewArgs + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/menu/providers/SubMenuProvider.cfc b/modules/contentbox/models/menu/providers/SubMenuProvider.cfc index 2dfd99c89b..ff578da98c 100644 --- a/modules/contentbox/models/menu/providers/SubMenuProvider.cfc +++ b/modules/contentbox/models/menu/providers/SubMenuProvider.cfc @@ -8,24 +8,24 @@ component implements="contentbox.models.menu.providers.IMenuItemProvider" extends ="contentbox.models.menu.providers.BaseProvider" - accessors =true + accessors ="#true#" { - - /* ********************************************************************* - ** DI - ********************************************************************* */ + /********************************************************************** + * ** DI + **********************************************************************/ property name="menuService" inject="id:menuService@contentbox"; + property name="requestService" inject="coldbox:requestService"; - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ /** * Constructor */ - public SubMenuProvider function init(){ + public SubMenuProvider function init() { setName( "SubMenu" ); setType( "SubMenu" ); setIconClass( "fa fa-bars" ); @@ -33,15 +33,19 @@ component setDescription( "A menu item which encapsulates another menu" ); return this; } + /** * Retrieves template for use in admin screens for this type of menu item provider * * @menuItem.hint The menu item object * @options.hint Additional arguments to be used in the method */ - public string function getAdminTemplate( required any menuItem, required struct options = {} ){ - var rc = requestService.getContext().getCollection(); - var criteria = menuService.newCriteria(); + public string function getAdminTemplate( + required any menuItem, + required struct options = {} + ) { + var rc = requestService.getContext().getCollection(); + var criteria = menuService.newCriteria(); var existingSlug = ""; if ( structKeyExists( rc, "menuID" ) && len( rc.menuID ) ) { criteria.ne( "menuID", rc.menuID ); @@ -49,31 +53,35 @@ component if ( !isNull( arguments.menuItem.getMenuSlug() ) ) { existingSlug = arguments.menuItem.getMenuSlug(); } - var menus = criteria.list( sortOrder = "title ASC" ); - var viewArgs = { menus : menus, existingSlug : existingSlug }; + var menus = criteria.list( sortOrder = "title ASC" ); + var viewArgs = { menus: menus, existingSlug: existingSlug }; return variables.renderer.view( - view = "menus/providers/submenu/admin", - module = "contentbox-admin", - args = viewArgs - ); + view = "menus/providers/submenu/admin", + module = "contentbox-admin", + args = viewArgs + ); } + /** * Retrieves template for use in rendering menu item on the site * * @menuItem.hint The menu item object * @options.hint Additional arguments to be used in the method */ - public string function getDisplayTemplate( required any menuItem, required struct options = {} ){ + public string function getDisplayTemplate( + required any menuItem, + required struct options = {} + ) { var viewArgs = { - menuItem : arguments.menuItem, - data : arguments.menuItem.getMemento(), - slugCache : arguments.options.slugCache + menuItem : arguments.menuItem, + data : arguments.menuItem.getMemento(), + slugCache: arguments.options.slugCache }; return variables.renderer.externalView( - view = "/contentbox/models/menu/views/submenu/display", - module = "contentbox", - args = viewArgs - ); + view = "/contentbox/models/menu/views/submenu/display", + module = "contentbox", + args = viewArgs + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/menu/providers/URLProvider.cfc b/modules/contentbox/models/menu/providers/URLProvider.cfc index ad516c251a..8dbfbafe43 100644 --- a/modules/contentbox/models/menu/providers/URLProvider.cfc +++ b/modules/contentbox/models/menu/providers/URLProvider.cfc @@ -11,14 +11,14 @@ component accessors ="true" { - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ /** * Constructor */ - public URLProvider function init(){ + public URLProvider function init() { setName( "URL" ); setType( "URL" ); setIconClass( "fa fa-link" ); @@ -33,13 +33,16 @@ component * @menuItem.hint The menu item object * @options.hint Additional arguments to be used in the method */ - public string function getAdminTemplate( required any menuItem, required struct options = {} ){ - var viewArgs = { menuItem : arguments.menuItem }; + public string function getAdminTemplate( + required any menuItem, + required struct options = {} + ) { + var viewArgs = { menuItem: arguments.menuItem }; return variables.renderer.view( - view = "menus/providers/url/admin", - module = "contentbox-admin", - args = viewArgs - ); + view = "menus/providers/url/admin", + module = "contentbox-admin", + args = viewArgs + ); } /** @@ -48,16 +51,19 @@ component * @menuItem.hint The menu item object * @options.hint Additional arguments to be used in the method */ - public string function getDisplayTemplate( required any menuItem, required struct options = {} ){ + public string function getDisplayTemplate( + required any menuItem, + required struct options = {} + ) { var viewArgs = { - menuItem : arguments.menuItem, - data : arguments.menuItem.getMemento() + menuItem: arguments.menuItem, + data : arguments.menuItem.getMemento() }; return variables.renderer.externalView( - view = "/contentbox/models/menu/views/url/display", - module = "contentbox", - args = viewArgs - ); + view = "/contentbox/models/menu/views/url/display", + module = "contentbox", + args = viewArgs + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/menu/views/content/display.cfm b/modules/contentbox/models/menu/views/content/display.cfm index 58c99e8a87..535e2054ba 100644 --- a/modules/contentbox/models/menu/views/content/display.cfm +++ b/modules/contentbox/models/menu/views/content/display.cfm @@ -1,3 +1,3 @@ - #args.menuItem.getLabel()# + #args.menuItem.getLabel()# \ No newline at end of file diff --git a/modules/contentbox/models/menu/views/free/display.cfm b/modules/contentbox/models/menu/views/free/display.cfm index d6db7664f8..c3dc4d5a47 100644 --- a/modules/contentbox/models/menu/views/free/display.cfm +++ b/modules/contentbox/models/menu/views/free/display.cfm @@ -1,3 +1,3 @@ - #args.menuItem.getLabel()# + #args.menuItem.getLabel()# \ No newline at end of file diff --git a/modules/contentbox/models/menu/views/js/display.cfm b/modules/contentbox/models/menu/views/js/display.cfm index 1a969eda69..fe3e1a7009 100644 --- a/modules/contentbox/models/menu/views/js/display.cfm +++ b/modules/contentbox/models/menu/views/js/display.cfm @@ -1,9 +1,9 @@ - - - #args.menuItem.getLabel()# + + +#args.menuItem.getLabel()# \ No newline at end of file diff --git a/modules/contentbox/models/menu/views/media/display.cfm b/modules/contentbox/models/menu/views/media/display.cfm index af80bb4e52..a0204719e1 100644 --- a/modules/contentbox/models/menu/views/media/display.cfm +++ b/modules/contentbox/models/menu/views/media/display.cfm @@ -1,3 +1,3 @@ - #args.menuItem.getLabel()# + #args.menuItem.getLabel()# \ No newline at end of file diff --git a/modules/contentbox/models/menu/views/submenu/display.cfm b/modules/contentbox/models/menu/views/submenu/display.cfm index 276d00a553..6fa775cb82 100644 --- a/modules/contentbox/models/menu/views/submenu/display.cfm +++ b/modules/contentbox/models/menu/views/submenu/display.cfm @@ -1,4 +1,7 @@ - #args.menuItem.getLabel()# - #cb.menu( slug="#args.data.menuSlug#", type="html", slugCache=args.slugCache )# + #args.menuItem.getLabel()##cb.menu( + slug = "#args.data.menuSlug#", + type = "html", + slugCache = args.slugCache + )# \ No newline at end of file diff --git a/modules/contentbox/models/menu/views/url/display.cfm b/modules/contentbox/models/menu/views/url/display.cfm index 7c5dbc1a3b..3d66b7da5d 100644 --- a/modules/contentbox/models/menu/views/url/display.cfm +++ b/modules/contentbox/models/menu/views/url/display.cfm @@ -1,3 +1,3 @@ - #args.menuItem.getLabel()# + #args.menuItem.getLabel()# \ No newline at end of file diff --git a/modules/contentbox/models/modules/Module.cfc b/modules/contentbox/models/modules/Module.cfc index 8f68daffa9..4c29b4a735 100644 --- a/modules/contentbox/models/modules/Module.cfc +++ b/modules/contentbox/models/modules/Module.cfc @@ -13,101 +13,99 @@ component cachename ="cbModule" cacheuse ="read-write" { - - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="moduleID" - column ="moduleID" + name="moduleID" + column="moduleID" fieldtype="id" generator="uuid" - length ="36" - ormtype ="string" - update ="false"; + length="36" + ormtype="string" + update="false"; property - name ="name" - column ="name" + name="name" + column="name" notnull="true" - length ="255" - index ="idx_moduleName"; + length="255" + index="idx_moduleName"; property - name ="title" - column ="title" + name="title" + column="title" notnull="false" - length ="255" + length="255" default=""; property - name ="version" - column ="version" + name="version" + column="version" notnull="false" - length ="255" + length="255" default="0"; property - name ="entryPoint" - column ="entryPoint" + name="entryPoint" + column="entryPoint" notnull="false" - length ="255" + length="255" default="" - index ="idx_entryPoint"; + index="idx_entryPoint"; property - name ="author" - column ="author" + name="author" + column="author" notnull="false" - length ="255" + length="255" default=""; property - name ="webURL" - column ="webURL" + name="webURL" + column="webURL" notnull="false" - length ="500" + length="500" default=""; property - name ="forgeBoxSlug" - column ="forgeBoxSlug" + name="forgeBoxSlug" + column="forgeBoxSlug" notnull="false" - length ="255" + length="255" default=""; property - name ="description" - column ="description" + name="description" + column="description" notnull="false" ormtype="text" - length ="8000" + length="8000" default=""; property - name ="isActive" - column ="isActive" + name="isActive" + column="isActive" notnull="true" ormtype="boolean" default="false" - index ="idx_activeModule"; + index="idx_activeModule"; property - name ="moduleType" - column ="moduleType" - default ="core" + name="moduleType" + column="moduleType" + default="core" dbdefault="'unknown'" - index ="idx_moduleType"; - - /* ********************************************************************* - ** PK + CONSTRAINTS - ********************************************************************* */ + index="idx_moduleType"; + /********************************************************************** + * ** PK + CONSTRAINTS + **********************************************************************/ this.pk = "moduleID"; this.memento = { - defaultIncludes : [ + defaultIncludes: [ "author", "description", "entryPoint", @@ -119,21 +117,21 @@ component "version", "webURL" ], - defaultExcludes : [ "" ] + defaultExcludes: [ ""] }; this.constraints = { - "name" : { required : true, size : "1..255" }, - "title" : { required : true, size : "1..255" }, - "version" : { required : false, size : "1..255" }, - "entryPoint" : { required : false, size : "1..255" }, - "author" : { required : false, size : "1..255" }, - "webURL" : { required : false, size : "1..500" }, - "forgeBoxSlug" : { required : false, size : "1..255" } + "name" : { required: true, size: "1..255" }, + "title" : { required: true, size: "1..255" }, + "version" : { required: false, size: "1..255" }, + "entryPoint" : { required: false, size: "1..255" }, + "author" : { required: false, size: "1..255" }, + "webURL" : { required: false, size: "1..500" }, + "forgeBoxSlug": { required: false, size: "1..255" } }; - function init(){ - variables.isActive = false; + function init() { + variables.isActive = false; variables.moduleType = "core"; super.init(); @@ -141,4 +139,4 @@ component return this; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/modules/ModuleService.cfc b/modules/contentbox/models/modules/ModuleService.cfc index 9c8b09c503..dc1f432600 100644 --- a/modules/contentbox/models/modules/ModuleService.cfc +++ b/modules/contentbox/models/modules/ModuleService.cfc @@ -5,19 +5,20 @@ * --- * Manage ContentBox Modules */ -component - extends ="cborm.models.VirtualEntityService" - accessors="true" - singleton - threadsafe -{ - +component extends ="cborm.models.VirtualEntityService" accessors="true" singleton threadsafe { // DI property name="settingService" inject="settingService@contentbox"; + property name="widgetService" inject="provider:widgetService@contentbox"; + property name="contentBoxSettings" inject="coldbox:moduleConfig:contentbox"; - property name="customModuleSettings" inject="coldbox:moduleConfig:contentbox-custom"; + + property + name="customModuleSettings" + inject="coldbox:moduleConfig:contentbox-custom"; + property name="coldboxModuleService" inject="coldbox:moduleService"; + property name="log" inject="logbox:logger:{this}"; /** @@ -60,27 +61,26 @@ component */ property name="moduleMap" type="struct"; - /** * Constructor */ - ModuleService function init(){ + ModuleService function init() { // init it super.init( entityName = "cbModule" ); - variables.customModulesPath = ""; + variables.customModulesPath = ""; variables.customModulesInvocationPath = ""; - variables.coreModulesPath = ""; - variables.coreModulesInvocationPath = ""; - variables.moduleWidgetCache = {}; - variables.moduleRegistry = {}; - variables.moduleConfigCache = {}; + variables.coreModulesPath = ""; + variables.coreModulesInvocationPath = ""; + variables.moduleWidgetCache = {}; + variables.moduleRegistry = {}; + variables.moduleConfigCache = {}; /** * Stores all module information when loaded: * { - * type : "The module type : core or custom", - * path : The absolute path, - * invocationPath : The invocation path + * type : "The module type : core or custom", + * path : The absolute path, + * invocationPath : The invocation path * } */ variables.moduleMap = {}; @@ -91,17 +91,17 @@ component /** * Executes after DI completion */ - function onDIComplete(){ + function onDIComplete() { // Setup Core Modules - variables.coreModulesPath = variables.contentBoxSettings.path & "/modules_user"; + variables.coreModulesPath = variables.contentBoxSettings.path & "/modules_user"; variables.coreModulesInvocationPath = variables.contentBoxSettings.invocationPath & ".modules_user"; // Setup Custom Modules - variables.customModulesPath = variables.customModuleSettings.path & "/_modules"; + variables.customModulesPath = variables.customModuleSettings.path & "/_modules"; variables.customModulesInvocationPath = variables.customModuleSettings.invocationPath & "._modules"; // Module Registry + Config Cache References - variables.moduleRegistry = variables.coldboxModuleService.getModuleRegistry(); + variables.moduleRegistry = variables.coldboxModuleService.getModuleRegistry(); variables.moduleConfigCache = variables.coldboxModuleService.getModuleConfigCache(); } @@ -113,7 +113,7 @@ component * * @return The module populated */ - any function populateModule( any module, any config ){ + any function populateModule( any module, any config ) { arguments.module.setTitle( arguments.config.title ?: "" ); arguments.module.setAuthor( arguments.config.author ?: "" ); arguments.module.setWebURL( arguments.config.webURL ?: "" ); @@ -131,9 +131,9 @@ component * * @return The persisted module or a new module object representing not found. */ - Module function findModuleByEntryPoint( required entryPoint ){ - var module = findWhere( { entryPoint : arguments.entryPoint } ); - return ( isNull( module ) ? new () : module ); + Module function findModuleByEntryPoint( required entryPoint ) { + var module = findWhere( { entryPoint: arguments.entryPoint } ); + return ( isNull( module ) ? new() : module ); } /** @@ -144,12 +144,12 @@ component * * @return struct:{ count:numeric, modules:array of objects } */ - struct function findModules( isActive = "any", moduleType ){ - var results = {}; + struct function findModules( isActive = "any", moduleType ) { + var results = {}; var criteria = newCriteria(); // isApproved filter - if ( !isNull( arguments.isActive ) AND arguments.isActive NEQ "any" ) { + if ( !isNull( arguments.isActive ) && arguments.isActive NEQ "any" ) { criteria.isEq( "isActive", javacast( "Boolean", arguments.isActive ) ); } @@ -159,7 +159,7 @@ component } // run criteria query and projections count - results.count = criteria.count(); + results.count = criteria.count(); results.modules = criteria.list( sortOrder = "title", asQuery = false ); return results; @@ -172,14 +172,16 @@ component * * @return The invocation path or empty if not found */ - string function getModuleWidgetInvocationPath( required string widgetName ){ + string function getModuleWidgetInvocationPath( required string widgetName ) { var path = ""; // if widget name is in module widget cache, return its invocation path if ( structKeyExists( variables.moduleWidgetCache, arguments.widgetName ) ) { path = variables.moduleWidgetCache[ arguments.widgetName ].invocationPath; } else { - log.error( "Could not find #arguments.widgetname# widget in the module." ); + log.error( + "Could not find #arguments.widgetname# widget in the module." + ); } return path; } @@ -190,24 +192,27 @@ component * @name The name of the module to register * @type The type of module: core or custom */ - Module function registerNewModule( required name, required type ){ - var thisPath = variables[ arguments.type & "ModulesPath" ]; + Module function registerNewModule( required name, required type ) { + var thisPath = variables[ arguments.type & "ModulesPath" ]; var thisInvocationPath = variables[ arguments.type & "ModulesInvocationPath" ]; if ( fileExists( thisPath & "/#arguments.name#/ModuleConfig.cfc" ) ) { - var oConfig = createObject( "component", thisInvocationPath & ".#arguments.name#.ModuleConfig" ); - var oModule = new ( { name : arguments.name, moduleType : arguments.type } ); + var oConfig = createObject( + "component", + thisInvocationPath & ".#arguments.name#.ModuleConfig" + ); + var oModule = new( { name: arguments.name, moduleType: arguments.type } ); save( populateModule( oModule, oConfig ) ); return oModule; } else { log.error( - "Cannot register new module #arguments.name# as it is not a valid ContentBox Module. No ModuleConfig.cfc found." - ); + "Cannot register new module #arguments.name# as it is not a valid ContentBox Module. No ModuleConfig.cfc found." + ); } - return new ( { name : arguments.name } ); + return new( { name: arguments.name } ); } /** @@ -215,9 +220,9 @@ component * * @name The module to deactivate */ - ModuleService function deactivateModule( required name ){ + ModuleService function deactivateModule( required name ) { // Get Module Record - var oModule = findWhere( { name : arguments.name } ); + var oModule = findWhere( { name: arguments.name } ); // deactivate record oModule.setIsActive( false ); @@ -230,8 +235,13 @@ component if ( structKeyExists( config, "onDeactivate" ) ) { try { config.onDeactivate(); - } catch ( Any e ) { - log.error( "Error deactivating module: #arguments.name# with #e.message & e.detail#", e ); + } catch (Any e) { + log.error( + "Error deactivating module: #arguments.name# with #e.message & e.detail#", + e + ); + + // dont' throw. just log and continue deactivating modules. } } @@ -250,26 +260,13 @@ component return this; } - /** - * Detach coldbox module configuration registrations - * - * @name The name of the module to detach - */ - private ModuleService function detachColdBoxModuleRegistration( required name ){ - // Verify in module registry - if ( structKeyExists( variables.moduleRegistry, arguments.name ) ) { - structDelete( variables.moduleRegistry, arguments.name ); - } - return this; - } - /** * Activate a module from ContentBox * * @name The name of the module to activate */ - ModuleService function activateModule( required name ){ - var oModule = findWhere( { name : arguments.name } ); + ModuleService function activateModule( required name ) { + var oModule = findWhere( { name: arguments.name } ); var sModuleMap = variables.moduleMap[ arguments.name ]; // Set module as active @@ -287,7 +284,7 @@ component if ( structKeyExists( oConfig, "onActivate" ) ) { try { oConfig.onActivate(); - } catch ( Any e ) { + } catch (Any e) { // deactivate module, it did not activate correctly oModule.setIsActive( false ); // deactivate from ColdBox as it did not activate correctly @@ -312,12 +309,15 @@ component * * @name The name of the module to delete */ - ModuleService function deleteModule( required name ){ + ModuleService function deleteModule( required name ) { var moduleEntry = variables.moduleMap[ arguments.name ]; // Try to do an onDelete() callback if it exists if ( fileExists( moduleEntry.path & "/#arguments.name#/ModuleConfig.cfc" ) ) { - var oConfig = createObject( "component", moduleEntry.invocationPath & ".#arguments.name#.ModuleConfig" ); + var oConfig = createObject( + "component", + moduleEntry.invocationPath & ".#arguments.name#.ModuleConfig" + ); if ( structKeyExists( oConfig, "onDelete" ) ) { oConfig.onDelete(); } @@ -335,7 +335,7 @@ component /** * Reset all modules by deactivating all of them and cleaning our db history */ - ModuleService function resetModules(){ + ModuleService function resetModules() { var aModules = list( asQuery = false ); transaction { @@ -356,28 +356,29 @@ component return this; } - - /** * Startup the service. This iterates through all modules on disk and if it finds a module that it has not been * registered, it will register it. If it loads a module that is registered and marked as active it will activate it. */ - ModuleService function startup(){ + ModuleService function startup() { // Get all modules var aModules = getAll(); // Register ColdBox Module Closure - var registerColdBoxModule = function( name, moduleType, invocationPath, path ){ + var registerColdBoxModule = function( name, moduleType, invocationPath, path ) { // var oModule = findWhere( { name : arguments.name } ); - var oModule = aModules.reduce( function( results, thisModule ){ - return ( thisModule.getName() == name ? thisModule : results ); - }, {} ); + var oModule = aModules.reduce( + function( results, thisModule ) { + return ( thisModule.getName() == name ? thisModule : results ); + }, + {} + ); // Register type lookup for faster finding, instead of querying the db. variables.moduleMap[ arguments.name ] = { - type : arguments.moduleType, - path : arguments.path, - invocationPath : arguments.invocationPath + type : arguments.moduleType, + path : arguments.path, + invocationPath: arguments.invocationPath }; // check if module already in database records or new @@ -388,12 +389,10 @@ component } // If we get here, the module is loaded in the database now - if ( oModule.getIsActive() AND !structKeyExists( variables.moduleRegistry, arguments.name ) ) { + if ( oModule.getIsActive() && !structKeyExists( variables.moduleRegistry, arguments.name ) ) { // Register with ColdBox now - variables.coldboxModuleService.registerModule( - moduleName = arguments.name, - invocationPath = arguments.invocationPath - ); + variables.coldboxModuleService.registerModule( moduleName = arguments.name, + invocationPath = arguments.invocationPath ); // Module registered, move to activation return true; } @@ -403,49 +402,68 @@ component }; // Register and Activate Core Modules First - getModulesOnDisk( variables.coreModulesPath ) - .filter( function( name ){ - return registerColdBoxModule( - arguments.name, - "core", - variables.coreModulesInvocationPath, - variables.coreModulesPath - ); - } ) - .each( function( name ){ - variables.coldboxModuleService.activateModule( arguments.name ); - } ); + getModulesOnDisk( variables.coreModulesPath ).filter( + function( name ) { + return registerColdBoxModule( + arguments.name, + "core", + variables.coreModulesInvocationPath, + variables.coreModulesPath + ); + } + ).each( + function( name ) { + variables.coldboxModuleService.activateModule( arguments.name ); + } + ); // Register and Activate Custom Modules - getModulesOnDisk( variables.customModulesPath ) - .filter( function( name ){ - return registerColdBoxModule( - arguments.name, - "custom", - variables.customModulesInvocationPath, - variables.customModulesPath - ); - } ) - .each( function( name ){ - variables.coldboxModuleService.activateModule( arguments.name ); - } ); + getModulesOnDisk( variables.customModulesPath ).filter( + function( name ) { + return registerColdBoxModule( + arguments.name, + "custom", + variables.customModulesInvocationPath, + variables.customModulesPath + ); + } + ).each( + function( name ) { + variables.coldboxModuleService.activateModule( arguments.name ); + } + ); // build widget cache buildModuleWidgetsCache( - aModules.filter( function( thisModule ){ - return arguments.thisModule.getIsActive(); - } ) + aModules.filter( + function( thisModule ) { + return arguments.thisModule.getIsActive(); + } + ) ); return this; } + /** + * Detach coldbox module configuration registrations + * + * @name The name of the module to detach + */ + private ModuleService function detachColdBoxModuleRegistration( required name ) { + // Verify in module registry + if ( structKeyExists( variables.moduleRegistry, arguments.name ) ) { + structDelete( variables.moduleRegistry, arguments.name ); + } + return this; + } + /** * Iterates over all registered, active modules and sets any found widgets into a cache in moduleservice * * @modules Optional passed array to use to build the module cache with, else query the database */ - private ModuleService function buildModuleWidgetsCache( array modules ){ + private ModuleService function buildModuleWidgetsCache( array modules ) { // Init Module Widget Cache variables.moduleWidgetCache = {}; @@ -455,41 +473,59 @@ component } // Process Module Widgets - arguments.modules - .filter( function( thisModule ){ - // Active and On Disk Module? - if ( variables.moduleMap.keyExists( thisModule.getName() ) ) { - return true; - } - - // Deactivate it, not fond in registry, might be an orphaned record - if ( log.canWarn() ) { - log.warn( "Orphaned module discovered: #thisModule.getName()#, deactiving it from the database" ); + arguments + .modules + .filter( + function( thisModule ) { + if ( variables.moduleMap.keyExists( thisModule.getName() ) ) { + return true; + } + + if ( log.canWarn() ) { + log.warn( + "Orphaned module discovered: #thisModule.getName()#, deactiving it from the database" + ); + } + deactivateModule( thisModule.getName() ); + return false; } - deactivateModule( thisModule.getName() ); - return false; - } ) - .each( function( thisModule ){ - // Module reference maps pointer - var moduleRecord = variables.moduleMap[ thisModule.getName() ]; - // Widgets path + local Reference - var thisWidgetsPath = moduleRecord.path & "/" & thisModule.getName() & "/widgets"; - - // check that module widgets folder exists on disk, if so, iterate and register - if ( directoryExists( thisWidgetsPath ) ) { - directoryList( thisWidgetsPath, false, "name", "*.cfc" ).each( function( thisWidget ){ - var widgetName = reReplaceNoCase( thisWidget, ".cfc", "", "all" ); - // Store Record - variables.moduleWidgetCache[ widgetName & "@" & thisModule.getName() ] = { - name : widgetName, - invocationPath : moduleRecord.invocationPath & ".#thisModule.getName()#.widgets.#widgetName#", - path : thisWidgetsPath & "/" & thisWidget, - module : thisModule.getName() - }; - } ); + ) + // Active and On Disk Module? + + // Deactivate it, not fond in registry, might be an orphaned record + + .each( + function( thisModule ) { + var moduleRecord = variables.moduleMap[ thisModule.getName() ]; + + var thisWidgetsPath = moduleRecord.path & "/" & thisModule.getName() & "/widgets"; + + if ( directoryExists( thisWidgetsPath ) ) { + directoryList( + thisWidgetsPath, + false, + "name", + "*.cfc" + ).each( + function( thisWidget ) { + var widgetName = reReplaceNoCase( + thisWidget, + ".cfc", + "", + "all" + ); + + variables.moduleWidgetCache[ widgetName & "@" & thisModule.getName() ] = { + name : widgetName, + invocationPath: moduleRecord.invocationPath & ".#thisModule.getName()#.widgets.#widgetName#", + path : thisWidgetsPath & "/" & thisWidget, + module : thisModule.getName() + }; + } + ); + } } - // end if widgets found - } ); + ); // Force Reload all widgets variables.widgetService.getWidgets( reload = true ); @@ -504,7 +540,7 @@ component * * @return An array of names found on disk */ - private array function getModulesOnDisk( required path ){ + private array function getModulesOnDisk( required path ) { // path, recurse, listInfo, filter, sort, type return directoryList( arguments.path, @@ -513,9 +549,11 @@ component "", "name asc", "dir" - ).filter( function( name ){ - return ( left( name, 1 ) neq "." ); - } ); + ).filter( + function( name ) { + return ( left( name, 1 ) NEQ "." ); + } + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/modules/custom/ModuleConfigBase.cfc b/modules/contentbox/models/modules/custom/ModuleConfigBase.cfc index 98ca6802b6..5c3759f508 100644 --- a/modules/contentbox/models/modules/custom/ModuleConfigBase.cfc +++ b/modules/contentbox/models/modules/custom/ModuleConfigBase.cfc @@ -9,32 +9,31 @@ * - modules - custom modules */ component { - // Module Properties - this.title = "ContentBox Custom Module"; - this.author = "Ortus Solutions, Corp"; - this.webURL = "https://www.ortussolutions.com"; - this.description = "This module is where all custom user assets can be placed and version controlled"; - this.viewParentLookup = true; + this.title = "ContentBox Custom Module"; + this.author = "Ortus Solutions, Corp"; + this.webURL = "https://www.ortussolutions.com"; + this.description = "This module is where all custom user assets can be placed and version controlled"; + this.viewParentLookup = true; this.layoutParentLookup = true; // URL Entry Point - this.entryPoint = "cbCustom"; + this.entryPoint = "cbCustom"; // Model Namespace - this.modelNamespace = "contentbox-custom"; + this.modelNamespace = "contentbox-custom"; // CF Mapping - this.cfmapping = "contentbox-custom"; + this.cfmapping = "contentbox-custom"; // ContentBox must be loaded first - this.dependencies = [ "contentbox" ]; + this.dependencies = [ "contentbox"]; /** * Configure Module */ - function configure(){ + function configure() { // contentbox settings settings = {}; // CB Module Conventions - conventions = { layoutsLocation : "_themes", viewsLocation : "_themes" }; + conventions = { layoutsLocation: "_themes", viewsLocation: "_themes" }; // Parent Affected Settings parentSettings = {}; @@ -42,7 +41,7 @@ component { // interceptor settings interceptorSettings = { // ContentBox Custom Events - customInterceptionPoints : [] + customInterceptionPoints: [] }; // interceptors @@ -52,21 +51,24 @@ component { /** * Development tier */ - function development(){ + function development() { + } /** * Fired when the module is registered and activated. */ - function onLoad(){ + function onLoad() { + } /** * Fired when the module is unregistered and unloaded */ - function onUnload(){ + function onUnload() { + } - /************************************** PRIVATE *********************************************/ -} + /************************************** PRIVATE *********************************************/ +} \ No newline at end of file diff --git a/modules/contentbox/models/rss/RSSCacheCleanup.cfc b/modules/contentbox/models/rss/RSSCacheCleanup.cfc index 0483b28f0e..97fc76f192 100644 --- a/modules/contentbox/models/rss/RSSCacheCleanup.cfc +++ b/modules/contentbox/models/rss/RSSCacheCleanup.cfc @@ -1,45 +1,47 @@ -/** -******************************************************************************** -ContentBox - A Modular Content Platform -Copyright 2012 by Luis Majano and Ortus Solutions, Corp -www.ortussolutions.com -******************************************************************************** -Apache License, Version 2.0 - -Copyright Since [2012] [Luis Majano and Ortus Solutions,Corp] - -Licensed under the Apache License, Version 2.0 (the "License" ); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -******************************************************************************** -* This interceptor monitors new comments and new entries to clear RSS cache entries -*/ +/** + * ******************************************************************************** + * ContentBox - A Modular Content Platform + * Copyright 2012 by Luis Majano and Ortus Solutions, Corp + * www.ortussolutions.com + * ******************************************************************************** + * Apache License, Version 2.0 + * + * Copyright Since [2012] [Luis Majano and Ortus Solutions,Corp] + * + * Licensed under the Apache License, Version 2.0 (the "License" ); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ******************************************************************************** + * This interceptor monitors new comments and new entries to clear RSS cache entries + */ component extends="coldbox.system.Interceptor" { // Listen when entries are saved - function cbadmin_postEntrySave( event, data ){ + function cbadmin_postEntrySave( event, data ) { getInstance( "rssService@contentbox" ).clearCaches(); } // Listen when entries are removed - function cbadmin_postEntryRemove( event, data ){ + function cbadmin_postEntryRemove( event, data ) { getInstance( "rssService@contentbox" ).clearCaches(); } // Listen when comments are made - function cbui_onCommentPost( event, data ){ - getInstance( "rssService@contentbox" ).clearCaches( - comments = true, - slug = arguments.data.comment.getRelatedContent().getSlug() - ); + function cbui_onCommentPost( event, data ) { + getInstance( "rssService@contentbox" ).clearCaches( comments = true, + slug = arguments + .data + .comment + .getRelatedContent() + .getSlug() ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/rss/RSSService.cfc b/modules/contentbox/models/rss/RSSService.cfc index 96ceba7852..a3e81104e2 100755 --- a/modules/contentbox/models/rss/RSSService.cfc +++ b/modules/contentbox/models/rss/RSSService.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -7,443 +7,463 @@ */ component singleton { - // DI - property name="entryService" inject="entryService@contentbox"; - property name="pageService" inject="pageService@contentbox"; - property name="contentService" inject="contentService@contentbox"; - property name="commentService" inject="commentService@contentbox"; - property name="CBHelper" inject="CBHelper@contentbox"; - property name="feedGenerator" inject="feedGenerator@cbfeeds"; - property name="log" inject="logbox:logger:{this}"; - - /** - * Constructor - * - * @settingService.inject id:settingService@contentbox - * @cacheBox.inject cachebox - */ - RSSService function init( required settingService, required cacheBox ){ - // Dependencies - variables.settingService = arguments.settingService; - variables.cacheBox = arguments.cacheBox; - // Get all settings - var settings = settingService.getAllSettings(); - // setup the user selected cache provider - variables.cache = cacheBox.getCache( settings.cb_rss_cacheName ); - - return this; - } - - /************************************** PUBLIC *********************************************/ - - /** - * Clean RSS caches asynchronously - * - * @comments Clear comment caches or not, defaults to false - * @slug The content slug to clear on - */ - RSSService function clearCaches( boolean comments = false, string slug = "" ){ - var cacheKey = ""; - - // compose cache key - if ( arguments.comments ) { - cacheKey = "cb-feeds-#cgi.HTTP_HOST#-content-comments-"; - } else { - cacheKey = "cb-feeds-#cgi.HTTP_HOST#-content"; - } - - // clear by snippet - variables.cache.clearByKeySnippet( keySnippet = cacheKey, async = false ); - - // log - if ( variables.log.canInfo() ) { - variables.log.info( - "Sent clear command using the following content key: #cacheKey# from provider: #variables.cache.getName()#" - ); - } - - return this; - } - - /** - * Clean All RSS caches NOW BABY, NOW! - */ - RSSService function clearAllCaches( boolean async = false ){ - variables.cache.clearByKeySnippet( keySnippet = "cb-feeds", async = arguments.async ); - return this; - } - - /** - * Build RSS feeds for contentbox content objects - * - * @slug The page or entry slug to filter on. - * @comments Retrieve the comments RSS feed or content feed, defaults to false - * @category Filter the content feed with categories - * @contentType The contentType to build an RSS feed on. Empty is for the site. Available content types are [page,entry] - * @siteID The site Id to filter on - */ - function getRSS( - string slug = "", - boolean comments = false, - category = "", - contentType = "", - string siteID = "" - ){ - var settings = settingService.getAllSettings(); - var rssFeed = ""; - var cacheKey = ""; - - // Comments cache Key - if ( arguments.comments ) { - cacheKey = "cb-feeds-#cgi.HTTP_HOST#-content-comments-#arguments.slug#"; - } - // Entries cache Key - else { - cacheKey = "cb-feeds-#cgi.HTTP_HOST#-content-#hash( arguments.category & arguments.contentType )#"; - } - - // Retrieve via caching? and caching active - if ( settings.cb_rss_caching ) { - var rssFeed = variables.cache.get( cacheKey ); - if ( !isNull( rssFeed ) ) { - return rssFeed; - } - } - - // Content Type - switch ( arguments.contentType ) { - // Pages - case "page": { - // Building comment feed or content feed - if ( arguments.comments ) { - arguments.contentType = "Page"; - rssfeed = buildCommentFeed( argumentCollection = arguments ); - } else { - rssfeed = buildPageFeed( argumentCollection = arguments ); - } - break; - } - // Blog - case "entry": { - // Building comment feed or content feed - if ( arguments.comments ) { - arguments.contentType = "Entry"; - rssfeed = buildCommentFeed( argumentCollection = arguments ); - } else { - rssfeed = buildEntryFeed( argumentCollection = arguments ); - } - break; - } - // Default Site - default: { - // Building comment feed or content feed - if ( arguments.comments ) { - rssfeed = buildCommentFeed( argumentCollection = arguments ); - } else { - rssfeed = buildContentFeed( argumentCollection = arguments ); - } - break; - } - } - // end content type switch - - // Cache it with settings - if ( settings.cb_rss_caching ) { - variables.cache.set( - cacheKey, - rssFeed, - settings.cb_rss_cachingTimeout, - settings.cb_rss_cachingTimeoutIdle - ); - } - - return rssFeed; - } - - /************************************** PRIVATE *********************************************/ - - /** - * Build entries feeds - * - * @category The category to filter on - * @siteID The site to filter on - */ - private function buildEntryFeed( string category = "", string siteID = "" ){ - var settings = settingService.getAllSettings(); - var entryResults = entryService.findPublishedContent( - category: arguments.category, - max : settings.cb_rss_maxEntries, - siteID : arguments.siteID - ); - var myArray = []; - var feedStruct = {}; - var columnMap = {}; - var qEntries = entityToQuery( entryResults.content ); - - // max checks - if ( settings.cb_rss_maxEntries lt entryResults.count ) { - entryResults.count = settings.cb_rss_maxEntries; - } - - // Create the column maps - columnMap.title = "title"; - columnMap.description = "content"; - columnMap.pubDate = "publishedDate"; - columnMap.link = "link"; - columnMap.author = "author"; - columnMap.category_tag = "categories"; - - // Add necessary columns to query - queryAddColumn( qEntries, "link", myArray ); - queryAddColumn( qEntries, "linkComments", myArray ); - queryAddColumn( qEntries, "author", myArray ); - queryAddColumn( qEntries, "categories", myArray ); - queryAddColumn( qEntries, "content", myArray ); - queryAddColumn( qEntries, "guid_permalink", myArray ); - queryAddColumn( qEntries, "guid_string", myArray ); - - // Attach permalinks - for ( var i = 1; i lte entryResults.count; i++ ) { - // build URL to entry - qEntries.link[ i ] = variables.CBHelper.linkEntry( qEntries.slug[ i ] ); - qEntries.guid_permalink[ i ] = false; - qEntries.guid_string[ i ] = variables.CBHelper.linkEntry( qEntries.slug[ i ] ); - ; - qEntries.author[ i ] = "#entryResults.content[ i ].getAuthorEmail()# (#entryResults.content[ i ].getAuthorName()#)"; - qEntries.linkComments[ i ] = variables.CBHelper.linkComments( entryResults.content[ i ] ); - qEntries.categories[ i ] = entryResults.content[ i ].getCategoriesList(); - if ( entryResults.content[ i ].hasExcerpt() ) { - qEntries.content[ i ] = entryResults.content[ i ].renderExcerpt(); - } else { - qEntries.content[ i ] = entryResults.content[ i ].renderContent(); - } - qEntries.content[ i ] = cleanupContent( qEntries.content[ i ] ); - } - - // Generate feed items - feedStruct.title = "Blog " & settings.cb_rss_title; - feedStruct.generator = settings.cb_rss_generator; - feedStruct.copyright = settings.cb_rss_copyright; - feedStruct.description = settings.cb_rss_description; - if ( len( settings.cb_rss_webmaster ) ) feedStruct.webmaster = settings.cb_rss_webmaster; - feedStruct.pubDate = now(); - feedStruct.lastbuilddate = now(); - feedStruct.link = variables.CBHelper.linkHome(); - feedStruct.items = qEntries; - - return variables.feedGenerator.createFeed( feedStruct, columnMap ); - } - - /** - * Build pages feeds - * - * @category The category to filter on - * @siteID The site to filter on - */ - private function buildPageFeed( string category = "", string siteID = "" ){ - var settings = settingService.getAllSettings(); - var pageResults = variables.pageService.findPublishedContent( - category: arguments.category, - max : settings.cb_rss_maxEntries, - siteID : arguments.siteID - ); - var myArray = []; - var feedStruct = {}; - var columnMap = {}; - var qPages = entityToQuery( pageResults.content ); - - // max checks - if ( settings.cb_rss_maxEntries lt pageResults.count ) { - pageResults.count = settings.cb_rss_maxEntries; - } - - // Create the column maps - columnMap.title = "title"; - columnMap.description = "content"; - columnMap.pubDate = "publishedDate"; - columnMap.link = "link"; - columnMap.author = "author"; - columnMap.category_tag = "categories"; - - // Add necessary columns to query - queryAddColumn( qPages, "link", myArray ); - queryAddColumn( qPages, "linkComments", myArray ); - queryAddColumn( qPages, "author", myArray ); - queryAddColumn( qPages, "categories", myArray ); - queryAddColumn( qPages, "content", myArray ); - queryAddColumn( qPages, "guid_permalink", myArray ); - queryAddColumn( qPages, "guid_string", myArray ); - - // Attach permalinks - for ( var i = 1; i lte pageResults.count; i++ ) { - // build URL to entry - qPages.link[ i ] = variables.CBHelper.linkPage( qPages.slug ); - qPages.author[ i ] = "#pageResults.content[ i ].getAuthorEmail()# (#pageResults.content[ i ].getAuthorName()#)"; - qPages.linkComments[ i ] = variables.CBHelper.linkComments( pageResults.content[ i ] ); - qPages.categories[ i ] = pageResults.content[ i ].getCategoriesList(); - qPages.guid_permalink[ i ] = false; - qPages.guid_string[ i ] = variables.CBHelper.linkPage( qPages.slug ); - if ( pageResults.content[ i ].hasExcerpt() ) { - qPages.content[ i ] = pageResults.content[ i ].renderExcerpt(); - } else { - qPages.content[ i ] = pageResults.content[ i ].renderContent(); - } - qPages.content[ i ] = cleanupContent( qPages.content[ i ] ); - } - - // Generate feed items - feedStruct.title = "Page " & settings.cb_rss_title; - feedStruct.generator = settings.cb_rss_generator; - feedStruct.copyright = settings.cb_rss_copyright; - feedStruct.description = settings.cb_rss_description; - if ( len( settings.cb_rss_webmaster ) ) feedStruct.webmaster = settings.cb_rss_webmaster; - feedStruct.pubDate = now(); - feedStruct.lastbuilddate = now(); - feedStruct.link = CBHelper.linkHome(); - feedStruct.items = qPages; - - return variables.feedGenerator.createFeed( feedStruct, columnMap ); - } - - /** - * Build content feeds - * - * @category The category to filter on - * @siteID The site to filter on - */ - private function buildContentFeed( string category = "", string siteID = "" ){ - var settings = variables.settingService.getAllSettings(); - var contentResults = variables.contentService.findPublishedContent( - category: arguments.category, - max : settings.cb_rss_maxEntries, - siteID : arguments.siteID - ); - var myArray = []; - var feedStruct = {}; - var columnMap = {}; - var qContent = entityToQuery( contentResults.content ); - - // max checks - if ( settings.cb_rss_maxEntries lt contentResults.count ) { - contentResults.count = settings.cb_rss_maxEntries; - } - - // Create the column maps - columnMap.title = "title"; - columnMap.description = "content"; - columnMap.pubDate = "publishedDate"; - columnMap.link = "link"; - columnMap.author = "author"; - columnMap.category_tag = "categories"; - - // Add necessary columns to query - queryAddColumn( qContent, "link", myArray ); - queryAddColumn( qContent, "linkComments", myArray ); - queryAddColumn( qContent, "author", myArray ); - queryAddColumn( qContent, "categories", myArray ); - queryAddColumn( qContent, "content", myArray ); - queryAddColumn( qContent, "guid_permalink", myArray ); - queryAddColumn( qContent, "guid_string", myArray ); - - // Attach permalinks - for ( var i = 1; i lte contentResults.count; i++ ) { - // Check for empty authors, just in case. - var authorEmail = len( contentResults.content[ i ].getAuthorEmail() ) ? contentResults.content[ i ].getAuthorEmail() : "nobody@nobody.com"; - var authorName = len( contentResults.content[ i ].getAuthorName() ) ? contentResults.content[ i ].getAuthorName() : "nobody"; - - // build URL to entry - qContent.link[ i ] = CBHelper.linkContent( contentResults.content[ i ] ); - qContent.author[ i ] = "#authorEmail# (#authorName#)"; - qContent.linkComments[ i ] = CBHelper.linkComments( contentResults.content[ i ] ); - qContent.categories[ i ] = contentResults.content[ i ].getCategoriesList(); - qContent.content[ i ] = cleanupContent( contentResults.content[ i ].renderContent() ); - qContent.guid_permalink[ i ] = false; - qContent.guid_string[ i ] = CBHelper.linkContent( contentResults.content[ i ] ); - } - - // Generate feed items - feedStruct.title = "Content " & settings.cb_rss_title; - feedStruct.generator = settings.cb_rss_generator; - feedStruct.copyright = settings.cb_rss_copyright; - feedStruct.description = settings.cb_rss_description; - if ( len( settings.cb_rss_webmaster ) ) feedStruct.webmaster = settings.cb_rss_webmaster; - feedStruct.pubDate = now(); - feedStruct.lastbuilddate = now(); - feedStruct.link = CBHelper.linkHome(); - feedStruct.items = qContent; - - return variables.feedGenerator.createFeed( feedStruct, columnMap ); - } - - /** - * Build comment feeds according to filtering elements - * - * @slug The content slug to filter on - * @contentType The content type discriminator to filter on - * @siteID The site to filter on - */ - private function buildCommentFeed( - string slug = "", - string contentType = "", - string siteID = "" - ){ - var settings = variables.settingService.getAllSettings(); - var commentResults = variables.commentService.findAllApproved( - contentID : variables.contentService.getIDBySlug( arguments.slug ), - contentType: arguments.contentType, - max : settings.cb_rss_maxComments, - siteID : arguments.siteID - ); - var myArray = []; - var feedStruct = {}; - var columnMap = {}; - var qComments = entityToQuery( commentResults.comments ); - - // Create the column maps - columnMap.title = "title"; - columnMap.description = "content"; - columnMap.pubDate = "createddate"; - columnMap.link = "link"; - columnMap.author = "rssAuthor"; - columnMap.category_tag = "categories"; - - // Add necessary columns to query - queryAddColumn( qComments, "title", myArray ); - queryAddColumn( qComments, "linkComments", myArray ); - queryAddColumn( qComments, "rssAuthor", myArray ); - queryAddColumn( qComments, "guid_permalink", myArray ); - queryAddColumn( qComments, "guid_string", myArray ); - - // Attach permalinks - for ( var i = 1; i lte commentResults.count; i++ ) { - // build URL to entry - qComments.title[ i ] = "Comment by #qComments.author[ i ]# on #commentResults.comments[ i ].getParentTitle()#"; - qComments.rssAuthor[ i ] = "#qComments.authorEmail# (#qComments.author#)"; - qComments.linkComments[ i ] = CBHelper.linkComment( commentResults.comments[ i ] ); - qComments.content[ i ] = cleanupContent( qComments.content[ i ] ); - qComments.guid_permalink[ i ] = false; - qComments.guid_string[ i ] = CBHelper.linkComment( commentResults.comments[ i ] ); - } - - // Generate feed items - feedStruct.title = "Comments " & settings.cb_rss_title; - feedStruct.generator = settings.cb_rss_generator; - feedStruct.copyright = settings.cb_rss_copyright; - feedStruct.description = settings.cb_rss_description; - if ( len( settings.cb_rss_webmaster ) ) feedStruct.webmaster = settings.cb_rss_webmaster; - feedStruct.pubDate = now(); - feedStruct.lastbuilddate = now(); - feedStruct.link = CBHelper.linkHome(); - feedStruct.items = qComments; - - return variables.feedGenerator.createFeed( feedStruct, columnMap ); - } - - /** - * Cleanup HTML to normal strings to avoid parsing issues - */ - private function cleanupContent( required content ){ - return reReplaceNoCase( arguments.content, "<[^>]*>", "", "all" ); - } + // DI + property name="entryService" inject="entryService@contentbox"; + + property name="pageService" inject="pageService@contentbox"; + + property name="contentService" inject="contentService@contentbox"; + + property name="commentService" inject="commentService@contentbox"; + + property name="CBHelper" inject="CBHelper@contentbox"; + + property name="feedGenerator" inject="feedGenerator@cbfeeds"; + + property name="log" inject="logbox:logger:{this}"; + + /** + * Constructor + * + * @settingService.inject id:settingService@contentbox + * @cacheBox.inject cachebox + */ + RSSService function init(required settingService, required cacheBox) { + // Dependencies + variables.settingService = arguments.settingService; + variables.cacheBox = arguments.cacheBox; + // Get all settings + var settings = settingService.getAllSettings(); + // setup the user selected cache provider + variables.cache = cacheBox.getCache(settings.cb_rss_cacheName); + + return this; + } + + /************************************** PUBLIC *********************************************/ + + /** + * Clean RSS caches asynchronously + * + * @comments Clear comment caches or not, defaults to false + * @slug The content slug to clear on + */ + RSSService function clearCaches(boolean comments = false, string slug = '') { + var cacheKey = ''; + + // compose cache key + if (arguments.comments) { + cacheKey = 'cb-feeds-#cgi.HTTP_HOST#-content-comments-'; + } else { + cacheKey = 'cb-feeds-#cgi.HTTP_HOST#-content'; + } + + // clear by snippet + variables.cache.clearByKeySnippet(keySnippet = cacheKey, async = false); + + // log + if (variables.log.canInfo()) { + variables.log.info( + 'Sent clear command using the following content key: #cacheKey# from provider: #variables.cache.getName()#' + ); + } + + return this; + } + + /** + * Clean All RSS caches NOW BABY, NOW! + */ + RSSService function clearAllCaches(boolean async = false) { + variables.cache.clearByKeySnippet(keySnippet = 'cb-feeds', async = arguments.async); + return this; + } + + /** + * Build RSS feeds for contentbox content objects + * + * @slug The page or entry slug to filter on. + * @comments Retrieve the comments RSS feed or content feed, defaults to false + * @category Filter the content feed with categories + * @contentType The contentType to build an RSS feed on. Empty is for the site. Available content types are [page,entry] + * @siteID The site Id to filter on + */ + function getRSS( + string slug = '', + boolean comments = false, + category = '', + contentType = '', + string siteID = '' + ) { + var settings = settingService.getAllSettings(); + var rssFeed = ''; + var cacheKey = ''; + + // Comments cache Key + if (arguments.comments) { + cacheKey = 'cb-feeds-#cgi.HTTP_HOST#-content-comments-#arguments.slug#'; + } else { + // Entries cache Key + cacheKey = 'cb-feeds-#cgi.HTTP_HOST#-content-#hash(arguments.category & arguments.contentType)#'; + } + + // Retrieve via caching? and caching active + if (settings.cb_rss_caching) { + var rssFeed = variables.cache.get(cacheKey); + if (!isNull(rssFeed)) { + return rssFeed; + } + } + + // Content Type + switch (arguments.contentType) { + // Pages + case 'page': { + // Building comment feed or content feed + if (arguments.comments) { + arguments.contentType = 'Page'; + rssfeed = buildCommentFeed(argumentCollection = arguments); + } else { + rssfeed = buildPageFeed(argumentCollection = arguments); + } + break; + } + // Blog + case 'entry': { + // Building comment feed or content feed + if (arguments.comments) { + arguments.contentType = 'Entry'; + rssfeed = buildCommentFeed(argumentCollection = arguments); + } else { + rssfeed = buildEntryFeed(argumentCollection = arguments); + } + break; + } + // Default Site + default: { + // Building comment feed or content feed + if (arguments.comments) { + rssfeed = buildCommentFeed(argumentCollection = arguments); + } else { + rssfeed = buildContentFeed(argumentCollection = arguments); + } + break; + } + } + // end content type switch + + // Cache it with settings + if (settings.cb_rss_caching) { + variables.cache.set( + cacheKey, + rssFeed, + settings.cb_rss_cachingTimeout, + settings.cb_rss_cachingTimeoutIdle + ); + } + + return rssFeed; + } + + /************************************** PRIVATE *********************************************/ + + /** + * Build entries feeds + * + * @category The category to filter on + * @siteID The site to filter on + */ + private function buildEntryFeed(string category = '', string siteID = '') { + var settings = settingService.getAllSettings(); + var entryResults = entryService.findPublishedContent( + category = arguments.category, + max = settings.cb_rss_maxEntries, + siteID = arguments.siteID + ); + var myArray = []; + var feedStruct = {}; + var columnMap = {}; + var qEntries = entityToQuery(entryResults.content); + + // max checks + if (settings.cb_rss_maxEntries LT entryResults.count) { + entryResults.count = settings.cb_rss_maxEntries; + } + + // Create the column maps + columnMap.title = 'title'; + columnMap.description = 'content'; + columnMap.pubDate = 'publishedDate'; + columnMap.link = 'link'; + columnMap.author = 'author'; + columnMap.category_tag = 'categories'; + + // Add necessary columns to query + queryAddColumn(qEntries, 'link', myArray); + queryAddColumn(qEntries, 'linkComments', myArray); + queryAddColumn(qEntries, 'author', myArray); + queryAddColumn(qEntries, 'categories', myArray); + queryAddColumn(qEntries, 'content', myArray); + queryAddColumn(qEntries, 'guid_permalink', myArray); + queryAddColumn(qEntries, 'guid_string', myArray); + + // Attach permalinks + for (var i = 1; i LTE entryResults.count; i++) { + var entrySlug = entryResults.content[i].getSlug(); + // build URL to entry + qEntries.link[i] = variables.CBHelper.linkEntry(entrySlug); + qEntries.guid_permalink[i] = false; + qEntries.guid_string[i] = variables.CBHelper.linkEntry(entrySlug); + + qEntries.author[i] = '#entryResults.content[i].getAuthorEmail()# (#entryResults.content[i].getAuthorName()#)'; + qEntries.linkComments[i] = variables.CBHelper.linkComments(entryResults.content[i]); + qEntries.categories[i] = entryResults.content[i].getCategoriesList(); + if (entryResults.content[i].hasExcerpt()) { + qEntries.content[i] = entryResults.content[i].renderExcerpt(); + } else { + qEntries.content[i] = entryResults.content[i].renderContent(); + } + qEntries.content[i] = cleanupContent(qEntries.content[i]); + } + + // Generate feed items + feedStruct.title = 'Blog ' & settings.cb_rss_title; + feedStruct.generator = settings.cb_rss_generator; + feedStruct.copyright = settings.cb_rss_copyright; + feedStruct.description = settings.cb_rss_description; + if (len(settings.cb_rss_webmaster)) { + feedStruct.webmaster = settings.cb_rss_webmaster; + } + feedStruct.pubDate = now(); + feedStruct.lastbuilddate = now(); + feedStruct.link = variables.CBHelper.linkHome(); + feedStruct.items = qEntries; + + return variables.feedGenerator.createFeed(feedStruct, columnMap); + } + + /** + * Build pages feeds + * + * @category The category to filter on + * @siteID The site to filter on + */ + private function buildPageFeed(string category = '', string siteID = '') { + var settings = settingService.getAllSettings(); + var pageResults = variables.pageService.findPublishedContent( + category = arguments.category, + max = settings.cb_rss_maxEntries, + siteID = arguments.siteID + ); + var myArray = []; + var feedStruct = {}; + var columnMap = {}; + var qPages = entityToQuery(pageResults.content); + + // max checks + if (settings.cb_rss_maxEntries LT pageResults.count) { + pageResults.count = settings.cb_rss_maxEntries; + } + + // Create the column maps + columnMap.title = 'title'; + columnMap.description = 'content'; + columnMap.pubDate = 'publishedDate'; + columnMap.link = 'link'; + columnMap.author = 'author'; + columnMap.category_tag = 'categories'; + + // Add necessary columns to query + queryAddColumn(qPages, 'link', myArray); + queryAddColumn(qPages, 'linkComments', myArray); + queryAddColumn(qPages, 'author', myArray); + queryAddColumn(qPages, 'categories', myArray); + queryAddColumn(qPages, 'content', myArray); + queryAddColumn(qPages, 'guid_permalink', myArray); + queryAddColumn(qPages, 'guid_string', myArray); + + // Attach permalinks + for (var i = 1; i LTE pageResults.count; i++) { + var pageSlug = pageResults.content[i].getSlug(); + // build URL to entry + qPages.link[i] = variables.CBHelper.linkPage(pageSlug); + qPages.author[i] = '#pageResults.content[i].getAuthorEmail()# (#pageResults.content[i].getAuthorName()#)'; + qPages.linkComments[i] = variables.CBHelper.linkComments(pageResults.content[i]); + qPages.categories[i] = pageResults.content[i].getCategoriesList(); + qPages.guid_permalink[i] = false; + qPages.guid_string[i] = variables.CBHelper.linkPage(pageSlug); + if (pageResults.content[i].hasExcerpt()) { + qPages.content[i] = pageResults.content[i].renderExcerpt(); + } else { + qPages.content[i] = pageResults.content[i].renderContent(); + } + qPages.content[i] = cleanupContent(qPages.content[i]); + } + + // Generate feed items + feedStruct.title = 'Page ' & settings.cb_rss_title; + feedStruct.generator = settings.cb_rss_generator; + feedStruct.copyright = settings.cb_rss_copyright; + feedStruct.description = settings.cb_rss_description; + if (len(settings.cb_rss_webmaster)) { + feedStruct.webmaster = settings.cb_rss_webmaster; + } + feedStruct.pubDate = now(); + feedStruct.lastbuilddate = now(); + feedStruct.link = CBHelper.linkHome(); + feedStruct.items = qPages; + + return variables.feedGenerator.createFeed(feedStruct, columnMap); + } + + /** + * Build content feeds + * + * @category The category to filter on + * @siteID The site to filter on + */ + private function buildContentFeed(string category = '', string siteID = '') { + var settings = variables.settingService.getAllSettings(); + var contentResults = variables.contentService.findPublishedContent( + category = arguments.category, + max = settings.cb_rss_maxEntries, + siteID = arguments.siteID + ); + var myArray = []; + var feedStruct = {}; + var columnMap = {}; + var qContent = entityToQuery(contentResults.content); + + // max checks + if (settings.cb_rss_maxEntries LT contentResults.count) { + contentResults.count = settings.cb_rss_maxEntries; + } + + // Create the column maps + columnMap.title = 'title'; + columnMap.description = 'content'; + columnMap.pubDate = 'publishedDate'; + columnMap.link = 'link'; + columnMap.author = 'author'; + columnMap.category_tag = 'categories'; + + // Add necessary columns to query + queryAddColumn(qContent, 'link', myArray); + queryAddColumn(qContent, 'linkComments', myArray); + queryAddColumn(qContent, 'author', myArray); + queryAddColumn(qContent, 'categories', myArray); + queryAddColumn(qContent, 'content', myArray); + queryAddColumn(qContent, 'guid_permalink', myArray); + queryAddColumn(qContent, 'guid_string', myArray); + + // Attach permalinks + for (var i = 1; i LTE contentResults.count; i++) { + // Check for empty authors, just in case. + var authorEmail = len(contentResults.content[i].getAuthorEmail()) + ? contentResults.content[i].getAuthorEmail() + : 'nobody@nobody.com'; + var authorName = len(contentResults.content[i].getAuthorName()) + ? contentResults.content[i].getAuthorName() + : 'nobody'; + + // build URL to entry + qContent.link[i] = CBHelper.linkContent(contentResults.content[i]); + qContent.author[i] = '#authorEmail# (#authorName#)'; + qContent.linkComments[i] = CBHelper.linkComments(contentResults.content[i]); + qContent.categories[i] = contentResults.content[i].getCategoriesList(); + qContent.content[i] = cleanupContent(contentResults.content[i].renderContent()); + qContent.guid_permalink[i] = false; + qContent.guid_string[i] = CBHelper.linkContent(contentResults.content[i]); + } + + // Generate feed items + feedStruct.title = 'Content ' & settings.cb_rss_title; + feedStruct.generator = settings.cb_rss_generator; + feedStruct.copyright = settings.cb_rss_copyright; + feedStruct.description = settings.cb_rss_description; + if (len(settings.cb_rss_webmaster)) { + feedStruct.webmaster = settings.cb_rss_webmaster; + } + feedStruct.pubDate = now(); + feedStruct.lastbuilddate = now(); + feedStruct.link = CBHelper.linkHome(); + feedStruct.items = qContent; + + return variables.feedGenerator.createFeed(feedStruct, columnMap); + } + + /** + * Build comment feeds according to filtering elements + * + * @slug The content slug to filter on + * @contentType The content type discriminator to filter on + * @siteID The site to filter on + */ + private function buildCommentFeed(string slug = '', string contentType = '', string siteID = '') { + var settings = variables.settingService.getAllSettings(); + var commentResults = variables.commentService.findAllApproved( + contentID = variables.contentService.getIDBySlug(arguments.slug), + contentType = arguments.contentType, + max = settings.cb_rss_maxComments, + siteID = arguments.siteID + ); + var myArray = []; + var feedStruct = {}; + var columnMap = {}; + var qComments = entityToQuery(commentResults.comments); + + // Create the column maps + columnMap.title = 'title'; + columnMap.description = 'content'; + columnMap.pubDate = 'createddate'; + columnMap.link = 'link'; + columnMap.author = 'rssAuthor'; + columnMap.category_tag = 'categories'; + + // Add necessary columns to query + queryAddColumn(qComments, 'title', myArray); + queryAddColumn(qComments, 'linkComments', myArray); + queryAddColumn(qComments, 'rssAuthor', myArray); + queryAddColumn(qComments, 'guid_permalink', myArray); + queryAddColumn(qComments, 'guid_string', myArray); + + // Attach permalinks + for (var i = 1; i LTE commentResults.count; i++) { + // build URL to entry + qComments.title[i] = 'Comment by #qComments.author[i]# on #commentResults.comments[i].getParentTitle()#'; + qComments.rssAuthor[i] = '#qComments.authorEmail# (#qComments.author#)'; + qComments.linkComments[i] = CBHelper.linkComment(commentResults.comments[i]); + qComments.content[i] = cleanupContent(qComments.content[i]); + qComments.guid_permalink[i] = false; + qComments.guid_string[i] = CBHelper.linkComment(commentResults.comments[i]); + } + + // Generate feed items + feedStruct.title = 'Comments ' & settings.cb_rss_title; + feedStruct.generator = settings.cb_rss_generator; + feedStruct.copyright = settings.cb_rss_copyright; + feedStruct.description = settings.cb_rss_description; + if (len(settings.cb_rss_webmaster)) { + feedStruct.webmaster = settings.cb_rss_webmaster; + } + feedStruct.pubDate = now(); + feedStruct.lastbuilddate = now(); + feedStruct.link = CBHelper.linkHome(); + feedStruct.items = qComments; + + return variables.feedGenerator.createFeed(feedStruct, columnMap); + } + + /** + * Cleanup HTML to normal strings to avoid parsing issues + */ + private function cleanupContent(required content) { + return reReplaceNoCase( + arguments.content, + '<[^>]*>', + '', + 'all' + ); + } } diff --git a/modules/contentbox/models/search/DBSearch.cfc b/modules/contentbox/models/search/DBSearch.cfc index 7a275f72b3..2cfb77a3fc 100644 --- a/modules/contentbox/models/search/DBSearch.cfc +++ b/modules/contentbox/models/search/DBSearch.cfc @@ -8,16 +8,17 @@ * @see contentbox.models.search.ISearchAdapter */ component accessors="true" singleton { - // DI property name="contentService" inject="contentService@contentbox"; + property name="cb" inject="cbHelper@contentbox"; + property name="wirebox" inject="wirebox"; /** * Constructor */ - DBSearch function init(){ + DBSearch function init() { return this; } @@ -36,32 +37,36 @@ component accessors="true" singleton { numeric max = 0, numeric offset = 0, string siteID = "" - ){ + ) { // get new search results object var searchResults = variables.wirebox.getInstance( "SearchResults@contentbox" ); - var sTime = getTickCount(); + var sTime = getTickCount(); try { var results = variables.contentService.searchContent( - offset : arguments.offset, - max : arguments.max, - searchTerm : arguments.searchTerm, - showInSearch: true, - contentTypes: "Page,Entry", - siteID : arguments.siteID - ); + offset = arguments.offset, + max = arguments.max, + searchTerm = arguments.searchTerm, + showInSearch = true, + contentTypes = "Page,Entry", + siteID = arguments.siteID + ); // populate the search results - searchResults.populate( { - results : results.content, - total : results.count, - searchTime : getTickCount() - sTime, - searchTerm : arguments.searchTerm, - error : false - } ); - } catch ( Any e ) { + searchResults.populate( + { + results : results.content, + total : results.count, + searchTime: getTickCount() - sTime, + searchTerm: arguments.searchTerm, + error : false + } + ); + } catch (Any e) { searchResults.setError( true ); - searchResults.setErrorMessages( [ "Error executing content search: #e.detail# #e.message#" ] ); + searchResults.setErrorMessages( + [ "Error executing content search: #e.detail# #e.message#"] + ); } return searchResults; @@ -72,7 +77,8 @@ component accessors="true" singleton { * * @return contentbox.models.search.ISearchAdapter */ - DBSearch function refresh(){ + DBSearch function refresh() { + } /** @@ -84,7 +90,7 @@ component accessors="true" singleton { required string searchTerm, numeric max = 0, numeric offset = 0 - ){ + ) { var searchResults = search( argumentCollection = arguments ); return renderSearchWithResults( searchResults ); } @@ -94,63 +100,66 @@ component accessors="true" singleton { * * @searchResults The search results object */ - any function renderSearchWithResults( required SearchResults searchResults ){ - var results = ""; + any function renderSearchWithResults( required SearchResults searchResults ) { + var results = ""; var searchItems = arguments.searchResults.getResults(); - var total = arguments.searchResults.getTotal(); - var searchTerm = arguments.searchResults.getSearchTerm(); - + var total = arguments.searchResults.getTotal(); + var searchTerm = arguments.searchResults.getSearchTerm(); // cfformat-ignore-start savecontent variable="results" { +// Render out the results or error if the results had errors +if ( arguments.searchResults.getError() ) { +writeOutput( +" +
    +

    Error Running Search

    +

    +#arrayToList( arguments.searchResults.getErrorMessages(), "
    " )# +

    +
    +" +); +} else { +writeOutput( +" +
    +
    +Found #total# results in #arguments.searchResults.getSearchTime()#ms! +
    +" +); +} - // Render out the results or error if the results had errors - if( arguments.searchResults.getError() ){ - writeOutput( " -
    -

    Error Running Search

    -

    - #arrayToList( - arguments.searchResults.getErrorMessages(), - "
    " - )# -

    -
    - " ); - } else { - writeOutput( " -
    -
    - Found #total# results in #arguments.searchResults.getSearchTime()#ms! -
    - " ); - } - - // Render out the items - for ( var item in searchItems ) { - writeOutput(" -
    - -
    -

    #highlightSearchTerm( searchTerm, stripHTML( item.renderContent() ) )#

    - #item.getContentType()# : #cb.linkContent( item )#
    -
    - "); - - if ( item.hasCategories() ) { - writeOutput( "
    Categories: " ); - for ( var categoryItem in #item.getCategoriesList()# ) { - writeOutput( " #categoryItem#" ); - } - writeOutput( "
    " ); - } +// Render out the items +for ( var item in searchItems ) { +writeOutput( +" +
    + +
    +

    #highlightSearchTerm( searchTerm, stripHTML( item.renderContent() ) )#

    +#item.getContentType()# : #cb.linkContent( item )#
    +
    +" +); + +if ( item.hasCategories() ) { +writeOutput( "
    Categories: " ); +for ( var categoryItem in item.getCategoriesList() ) { +writeOutput( +" #categoryItem#" +); +} +writeOutput( "
    " ); +} - writeOutput( "
    " ); - }; +writeOutput( "
    " ); +} - writeOutput( "
    " ); - } +writeOutput( "
    " ); +} // cfformat-ignore-end return results; @@ -159,8 +168,13 @@ component accessors="true" singleton { /** * utility to strip HTML */ - private function stripHTML( stringTarget ){ - return reReplaceNoCase( arguments.stringTarget, "<[^>]*>", "", "ALL" ); + private function stripHTML( stringTarget ) { + return reReplaceNoCase( + arguments.stringTarget, + "<[^>]*>", + "", + "ALL" + ); } /** @@ -169,23 +183,27 @@ component accessors="true" singleton { * @term The search term * @content The content searched */ - private function highlightSearchTerm( required term, required content ){ - var match = findNoCase( arguments.term, arguments.content ); - var end = 0; + private function highlightSearchTerm( required term, required content ) { + var match = findNoCase( arguments.term, arguments.content ); + var end = 0; var excerpt = ""; - if ( match lte 250 ) { + if ( match LTE 250 ) { match = 1; } end = match + len( arguments.term ) + 500; - if ( len( arguments.content ) gt 500 ) { - if ( match gt 1 ) { - excerpt = "..." & mid( arguments.content, match - 250, end - match ); + if ( len( arguments.content ) GT 500 ) { + if ( match GT 1 ) { + excerpt = "..." & mid( + arguments.content, + match - 250, + end - match + ); } else { excerpt = left( arguments.content, end ); } - if ( len( arguments.content ) gt end ) { + if ( len( arguments.content ) GT end ) { excerpt = excerpt & "..."; } } else { @@ -199,7 +217,8 @@ component accessors="true" singleton { "\1", "all" ); - } catch ( Any e ) { + } catch (Any e) { + } // remove images @@ -210,4 +229,4 @@ component accessors="true" singleton { return excerpt; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/search/ISearchAdapter.cfc b/modules/contentbox/models/search/ISearchAdapter.cfc index fa951293d7..53caf2cb92 100644 --- a/modules/contentbox/models/search/ISearchAdapter.cfc +++ b/modules/contentbox/models/search/ISearchAdapter.cfc @@ -53,6 +53,7 @@ interface { * * @return The search html */ - any function renderSearchWithResults( required contentbox.models.search.SearchResults searchResults ); - -} + any function renderSearchWithResults( + required contentbox.models.search.SearchResults searchResults + ); +} \ No newline at end of file diff --git a/modules/contentbox/models/search/SearchResults.cfc b/modules/contentbox/models/search/SearchResults.cfc index 19150d7476..459f71c4a6 100644 --- a/modules/contentbox/models/search/SearchResults.cfc +++ b/modules/contentbox/models/search/SearchResults.cfc @@ -6,7 +6,6 @@ * The official ContentBox Search Results Object */ component accessors="true" { - property name="results" type="any" @@ -22,10 +21,7 @@ component accessors="true" { type="numeric" hint="The amount of time it took for the search in milliseconds"; - property - name="searchTerm" - type="string" - hint="The search term used"; + property name="searchTerm" type="string" hint="The search term used"; property name="error" @@ -45,14 +41,14 @@ component accessors="true" { /** * Constructor */ - function init(){ - variables.results = []; - variables.searchTime = 0; - variables.total = 0; - variables.metadata = {}; - variables.error = false; + function init() { + variables.results = []; + variables.searchTime = 0; + variables.total = 0; + variables.metadata = {}; + variables.error = false; variables.errorMessages = []; - variables.searchTerm = ""; + variables.searchTerm = ""; return this; } @@ -62,7 +58,7 @@ component accessors="true" { * * @return SearchResults */ - any function populate( required struct memento ){ + any function populate( required struct memento ) { for ( var key in arguments.memento ) { if ( structKeyExists( variables, key ) ) { variables[ key ] = arguments.memento[ key ]; @@ -76,16 +72,16 @@ component accessors="true" { * * @return struct of { "results","searchTime","total","metadata","error","errorMessages","searchTerm" } */ - struct function getMemento(){ + struct function getMemento() { return { - "results" : results, - "searchTime" : searchTime, - "total" : total, - "metadata" : metadata, - "error" : error, - "errorMessages" : errorMessages, - "searchTerm" : searchTerm + "results" : results, + "searchTime" : searchTime, + "total" : total, + "metadata" : metadata, + "error" : error, + "errorMessages": errorMessages, + "searchTerm" : searchTerm }; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/search/SearchService.cfc b/modules/contentbox/models/search/SearchService.cfc index fa64dc5cdd..138d043290 100644 --- a/modules/contentbox/models/search/SearchService.cfc +++ b/modules/contentbox/models/search/SearchService.cfc @@ -6,15 +6,15 @@ * The official ContentBox Search Service */ component accessors="true" { - // DI property name="wirebox" inject="wirebox"; + property name="settingService" inject="settingService@contentbox"; /** * Constructor */ - SearchService function init(){ + SearchService function init() { return this; } @@ -22,8 +22,8 @@ component accessors="true" { * Return the actual ContentBox configured search adapter that should meet * the following interface: contentbox.models.search.ISearchAdapter */ - any function getSearchAdapter(){ + any function getSearchAdapter() { return variables.wirebox.getInstance( variables.settingService.getSetting( "cb_search_adapter" ) ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/security/Author.cfc b/modules/contentbox/models/security/Author.cfc index e373f57be3..8b065096c0 100644 --- a/modules/contentbox/models/security/Author.cfc +++ b/modules/contentbox/models/security/Author.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -14,214 +14,212 @@ component cachename ="cbAuthor" cacheuse ="read-write" { - - /* ********************************************************************* - ** DI - ********************************************************************* */ + /********************************************************************** + * ** DI + **********************************************************************/ property - name ="authorService" - inject ="provider:authorService@contentbox" + name="authorService" + inject="provider:authorService@contentbox" persistent="false"; property - name ="avatar" - inject ="provider:Avatar@contentbox" + name="avatar" + inject="provider:Avatar@contentbox" persistent="false"; - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="authorID" - column ="authorID" + name="authorID" + column="authorID" fieldtype="id" generator="uuid" - length ="36" - ormtype ="string" - update ="false"; + length="36" + ormtype="string" + update="false"; property - name ="firstName" - column ="firstName" - length ="100" + name="firstName" + column="firstName" + length="100" notnull="true" default=""; property - name ="lastName" - column ="lastName" - length ="100" + name="lastName" + column="lastName" + length="100" notnull="true" default=""; property - name ="email" - column ="email" - length ="255" + name="email" + column="email" + length="255" notnull="true" - index ="idx_email" + index="idx_email" default=""; property - name ="username" - column ="username" - length ="100" + name="username" + column="username" + length="100" notnull="true" - index ="idx_login" - unique ="true" + index="idx_login" + unique="true" default=""; property - name ="password" - column ="password" - length ="100" + name="password" + column="password" + length="100" notnull="true" - index ="idx_login" + index="idx_login" default=""; property - name ="isActive" - column ="isActive" + name="isActive" + column="isActive" ormtype="boolean" notnull="true" default="false" - index ="idx_login,idx_activeAuthor"; + index="idx_login,idx_activeAuthor"; property - name ="lastLogin" - column ="lastLogin" + name="lastLogin" + column="lastLogin" ormtype="timestamp" notnull="false"; property - name ="biography" - column ="biography" + name="biography" + column="biography" ormtype="text" notnull="false" - length ="8000" + length="8000" default=""; property - name ="preferences" - column ="preferences" + name="preferences" + column="preferences" ormtype="text" notnull="false" - length ="8000" + length="8000" default=""; property - name ="isPasswordReset" - column ="isPasswordReset" + name="isPasswordReset" + column="isPasswordReset" ormtype="boolean" notnull="true" default="false" - index ="idx_passwordReset"; + index="idx_passwordReset"; property - name ="is2FactorAuth" - column ="is2FactorAuth" + name="is2FactorAuth" + column="is2FactorAuth" ormtype="boolean" notnull="true" default="false" - index ="idx_2factorauth"; + index="idx_2factorauth"; - /* ********************************************************************* - ** RELATIONSHIPS - ********************************************************************* */ + /********************************************************************** + * ** RELATIONSHIPS + **********************************************************************/ // O2M -> Entries property - name ="entries" + name="entries" singularName="entry" - type ="array" - fieldtype ="one-to-many" - cfc ="contentbox.models.content.Entry" - fkcolumn ="FK_authorID" - inverse ="true" - lazy ="true" - cascade ="save-update" - batchsize ="10" - orderby ="publishedDate DESC"; + type="array" + fieldtype="one-to-many" + cfc="contentbox.models.content.Entry" + fkcolumn="FK_authorID" + inverse="true" + lazy="true" + cascade="save-update" + batchsize="10" + orderby="publishedDate DESC"; // O2M -> Pages property - name ="pages" + name="pages" singularName="page" - type ="array" - fieldtype ="one-to-many" - cfc ="contentbox.models.content.Page" - fkcolumn ="FK_authorID" - inverse ="true" - lazy ="true" - cascade ="save-update" - batchsize ="10" - orderby ="publishedDate DESC"; + type="array" + fieldtype="one-to-many" + cfc="contentbox.models.content.Page" + fkcolumn="FK_authorID" + inverse="true" + lazy="true" + cascade="save-update" + batchsize="10" + orderby="publishedDate DESC"; // M20 -> Role property - name ="role" - notnull ="true" + name="role" + notnull="true" fieldtype="many-to-one" - cfc ="contentbox.models.security.Role" - fkcolumn ="FK_roleID" - lazy ="true"; + cfc="contentbox.models.security.Role" + fkcolumn="FK_roleID" + lazy="true"; // M2M -> A-la-carte Author Permissions property - name ="permissions" - fieldtype ="many-to-many" - cascade ="save-update" - type ="array" - lazy ="true" - cfc ="contentbox.models.security.Permission" - fkcolumn ="FK_authorID" - linktable ="cb_authorPermissions" + name="permissions" + fieldtype="many-to-many" + cascade="save-update" + type="array" + lazy="true" + cfc="contentbox.models.security.Permission" + fkcolumn="FK_authorID" + linktable="cb_authorPermissions" inversejoincolumn="FK_permissionID" - orderby ="permission"; + orderby="permission"; // M2M -> A-la-carte Author Permission Groups property - name ="permissionGroups" - singularName ="permissionGroup" - fieldtype ="many-to-many" - type ="array" - lazy ="true" - inverse ="true" - cfc ="contentbox.models.security.PermissionGroup" - cascade ="all" - fkcolumn ="FK_authorID" - linktable ="cb_authorPermissionGroups" + name="permissionGroups" + singularName="permissionGroup" + fieldtype="many-to-many" + type="array" + lazy="true" + inverse="true" + cfc="contentbox.models.security.PermissionGroup" + cascade="all" + fkcolumn="FK_authorID" + linktable="cb_authorPermissionGroups" inversejoincolumn="FK_permissionGroupID" - orderby ="name"; + orderby="name"; - /* ********************************************************************* - ** CALCULATED FIELDS - ********************************************************************* */ + /********************************************************************** + * ** CALCULATED FIELDS + **********************************************************************/ - /* ********************************************************************* - ** NON PERSISTED PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** NON PERSISTED PROPERTIES + **********************************************************************/ // Non-persisted properties property - name ="loggedIn" + name="loggedIn" persistent="false" - default ="false" - type ="boolean"; + default="false" + type="boolean"; property name="permissionList" persistent="false"; - - /* ********************************************************************* - ** PK + CONSTRAINTS + MEMENTO - ********************************************************************* */ + /********************************************************************** + * ** PK + CONSTRAINTS + MEMENTO + **********************************************************************/ this.pk = "authorID"; this.memento = { // Default properties to serialize - defaultIncludes : [ + defaultIncludes: [ "firstName", "lastName", "email", @@ -238,7 +236,7 @@ component "numberOfContentStore" ], // Default Exclusions - defaultExcludes : [ + defaultExcludes: [ "entries", "pages", "permissions", @@ -247,43 +245,43 @@ component "isPasswordReset", "is2FactorAuth" ], - neverInclude : [ "password" ], + neverInclude: [ "password"], // Defaults - defaults : { "role" : {} } + defaults : { "role": {} } }; this.constraints = { - "firstName" : { required : true, size : "1..100" }, - "lastName" : { required : true, size : "1..100" }, - "email" : { - required : true, - size : "1..255", - type : "email", - validator : "UniqueValidator@cborm" + "firstName": { required: true, size: "1..100" }, + "lastName" : { required: true, size: "1..100" }, + "email" : { + required : true, + size : "1..255", + type : "email", + validator: "UniqueValidator@cborm" }, - "username" : { - required : true, - size : "1..100", - validator : "UniqueValidator@cborm" + "username": { + required : true, + size : "1..100", + validator: "UniqueValidator@cborm" }, - "password" : { required : true, size : "1..100" }, - "role" : { required : true } + "password": { required: true, size: "1..100" }, + "role" : { required: true } }; - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ /** * Constructor */ - function init(){ - variables.permissionList = []; - variables.loggedIn = false; - variables.isActive = true; + function init() { + variables.permissionList = []; + variables.loggedIn = false; + variables.isActive = true; variables.permissionGroups = []; - variables.isPasswordReset = false; - variables.is2FactorAuth = false; + variables.isPasswordReset = false; + variables.is2FactorAuth = false; // Setup empty preferences setPreferences( {} ); @@ -296,28 +294,28 @@ component /** * Get the total number of content items this author has created */ - numeric function getNumberOfContent(){ + numeric function getNumberOfContent() { return ( isLoaded() ? variables.authorService.getTotalContent( getAuthorId() ) : 0 ); } /** * Get the total number of entries this author has created */ - numeric function getNumberOfEntries(){ + numeric function getNumberOfEntries() { return ( isLoaded() ? variables.authorService.getTotalEntries( getAuthorId() ) : 0 ); } /** * Get the total number of pages this author has created */ - numeric function getNumberOfPages(){ + numeric function getNumberOfPages() { return ( isLoaded() ? variables.authorService.getTotalPages( getAuthorId() ) : 0 ); } /** * Get the total number of content store items this author has created */ - numeric function getNumberOfContentStore(){ + numeric function getNumberOfContentStore() { return ( isLoaded() ? variables.authorService.getTotalContentStoreItems( getAuthorId() ) : 0 ); } @@ -326,9 +324,9 @@ component * * @permission One or a list of permissions to check for access */ - boolean function hasPermission( required permission ){ + boolean function hasPermission( required permission ) { // cache deconstructed permissions in case it's called many times during a request. - if ( !arrayLen( variables.permissionList ) AND hasPermissions() ) { + if ( !arrayLen( variables.permissionList ) && hasPermissions() ) { variables.permissionList = arrayReduce( getPermissions(), ( result, item ) => { @@ -340,11 +338,9 @@ component // checks via role, then group permissions and then local permissions if ( - ( hasRole() && getRole().hasPermission( arguments.permission ) ) - OR - checkGroupPermissions( arguments.permission ) - OR - inPermissionList( arguments.permission ) + ( hasRole() && getRole().hasPermission( arguments.permission ) ) || + checkGroupPermissions( arguments.permission ) || + inPermissionList( arguments.permission ) ) { return true; } @@ -357,7 +353,7 @@ component * * @slug The slug to check */ - boolean function checkGroupPermissions( required slug ){ + boolean function checkGroupPermissions( required slug ) { // If no groups, just return false if ( !hasPermissionGroup() ) { return false; @@ -378,16 +374,16 @@ component * * @permission A list or array of permission to check */ - public function inPermissionList( required permission ){ - return arrayWrap( arguments.permission ) - .filter( ( item ) => variables.permissionList.findNoCase( arguments.item ) ) - .len(); + public function inPermissionList( required permission ) { + return arrayWrap( arguments.permission ).filter( + ( item ) => variables.permissionList.findNoCase( arguments.item ) + ).len(); } /** * Remove all permissions */ - Author function clearPermissions(){ + Author function clearPermissions() { if ( hasPermissions() ) { variables.permissions.clear(); } else { @@ -400,7 +396,7 @@ component /** * Remove all permission groups */ - Author function clearPermissionGroups(){ + Author function clearPermissionGroups() { if ( hasPermissionGroup() ) { variables.permissionGroups.clear(); } else { @@ -414,7 +410,7 @@ component * * @permissions The permissions array to override */ - Author function setPermissions( required array permissions ){ + Author function setPermissions( required array permissions ) { if ( hasPermissions() ) { variables.permissions.clear(); variables.permissions.addAll( arguments.permissions ); @@ -427,7 +423,7 @@ component /** * Shortcut Utlity function to get a list of all the permission groups this user belongs to. */ - string function getPermissionGroupsList( delimiter = "," ){ + string function getPermissionGroupsList( delimiter = "," ) { if ( hasPermissionGroup() ) { return arrayReduce( variables.permissionGroups, @@ -443,7 +439,7 @@ component * * @group The permission group to add */ - Author function addPermissionGroup( required group ){ + Author function addPermissionGroup( required group ) { // Only add if not already there. if ( !hasPermissionGroup( arguments.group ) ) { arrayAppend( variables.permissionGroups, arguments.group ); @@ -457,7 +453,7 @@ component * * @group The permission group to add */ - Author function removePermissionGroup( required group ){ + Author function removePermissionGroup( required group ) { // Only add if not already there. if ( hasPermissionGroup( arguments.group ) ) { arrayDelete( variables.permissionGroups, arguments.group ); @@ -470,17 +466,20 @@ component * Utility method to verify if an author has been logged in to the system or not. * This method does not account for permissions. Only for logged in status. */ - function isLoggedIn(){ + function isLoggedIn() { return getLoggedIn(); } /** * Get formatted lastLogin */ - string function getDisplayLastLogin( dateFormat = this.DATE_FORMAt, timeFormat = this.TIME_FORMAT ){ + string function getDisplayLastLogin( + dateFormat = this.DATE_FORMAt, + timeFormat = this.TIME_FORMAT + ) { var lastLogin = getLastLogin(); - if ( NOT isNull( lastLogin ) ) { + if ( !isNull( lastLogin ) ) { return dateFormat( lastLogin, arguments.dateFormat ) & " " & timeFormat( lastLogin, arguments.timeFormat ); } @@ -494,8 +493,13 @@ component * * @preferences.hint A struct of data or a JSON packet to store */ - Author function setPreferences( required any preferences ){ - lock name="user.#getAuthorID()#.preferences" type="exclusive" throwontimeout="true" timeout="5" { + Author function setPreferences( required any preferences ) { + lock + name ="user.#getAuthorID()#.preferences" + type ="exclusive" + throwontimeout="true" + timeout ="5" + { if ( isStruct( arguments.preferences ) ) { arguments.preferences = serializeJSON( arguments.preferences ); } @@ -508,18 +512,28 @@ component /** * Get all user preferences in inflated format */ - struct function getAllPreferences(){ - lock name="user.#getAuthorID()#.preferences" type="readonly" throwontimeout="true" timeout="5" { - return ( !isNull( preferences ) AND isJSON( preferences ) ? deserializeJSON( preferences ) : structNew() ); + struct function getAllPreferences() { + lock + name ="user.#getAuthorID()#.preferences" + type ="readonly" + throwontimeout="true" + timeout ="5" + { + return ( !isNull( preferences ) && isJSON( preferences ) ? deserializeJSON( preferences ) : structNew() ); } } /** * Get a preference, you can pass a default value if preference does not exist */ - any function getPreference( required name, defaultValue ){ + any function getPreference( required name, defaultValue ) { // get preference - lock name="user.#getAuthorID()#.preferences" type="readonly" throwontimeout="true" timeout="5" { + lock + name ="user.#getAuthorID()#.preferences" + type ="readonly" + throwontimeout="true" + timeout ="5" + { var allPreferences = getAllPreferences(); if ( structKeyExists( allPreferences, arguments.name ) ) { return allPreferences[ arguments.name ]; @@ -540,8 +554,8 @@ component /** * Set a preference in the user preferences */ - Author function setPreference( required name, required value ){ - var allPreferences = getAllPreferences(); + Author function setPreference( required name, required value ) { + var allPreferences = getAllPreferences(); allPreferences[ arguments.name ] = arguments.value; // store in lock mode return setPreferences( allPreferences ); @@ -552,14 +566,14 @@ component /** * A struct of custom claims to add to the JWT token */ - struct function getJwtCustomClaims(){ + struct function getJwtCustomClaims() { return {}; } /** * This function returns an array of all the scopes that should be attached to the JWT token that will be used for authorization. */ - array function getJwtScopes(){ + array function getJwtScopes() { return []; } @@ -568,14 +582,14 @@ component /** * Get the user's role name */ - string function getRoleName(){ + string function getRoleName() { return ( hasRole() ? getRole().getRole() : "" ); } /** * Retrieve full name */ - string function getFullName(){ + string function getFullName() { return getFirstname() & " " & getLastName(); } @@ -584,24 +598,24 @@ component * * @size The size of the avatar, defaults to 40 */ - string function getAvatarLink( numeric size = 40 ){ + string function getAvatarLink( numeric size = 40 ) { return ( isNull( getEmail() ) ? "" : variables.avatar.generateLink( getEmail(), arguments.size ) ); } /** * Utility method to get a snapshot of the user information */ - struct function getInfoSnapshot(){ + struct function getInfoSnapshot() { if ( isLoaded() ) { return { - "authorID" : getAuthorID(), - "name" : getFullName(), - "email" : getEmail(), - "avatarLink" : getAvatarLink() + "authorID" : getAuthorID(), + "name" : getFullName(), + "email" : getEmail(), + "avatarLink": getAvatarLink() }; } return {}; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/security/AuthorService.cfc b/modules/contentbox/models/security/AuthorService.cfc index 14df4f3a52..ac942d28c3 100755 --- a/modules/contentbox/models/security/AuthorService.cfc +++ b/modules/contentbox/models/security/AuthorService.cfc @@ -1,34 +1,42 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox * --- * Service to handle user operations. */ -component - extends ="cborm.models.VirtualEntityService" - accessors="true" - singleton -{ - +component extends ="cborm.models.VirtualEntityService" accessors="true" singleton { // DI property name="bCrypt" inject="BCrypt@BCrypt"; + property name="dateUtil" inject="DateUtil@contentbox"; + property name="CBHelper" inject="CBHelper@contentbox"; + property name="mailService" inject="mailService@cbmailservices"; + property name="permissionService" inject="permissionService@contentbox"; - property name="permissionGroupService" inject="permissionGroupService@contentbox"; + + property + name="permissionGroupService" + inject="permissionGroupService@contentbox"; + property name="renderer" inject="coldbox:renderer"; + property name="requestService" inject="coldbox:requestService"; + property name="roleService" inject="roleService@contentbox"; + property name="settingService" inject="provider:settingService@contentbox"; + property name="securityService" inject="provider:securityService@contentbox"; + property name="siteService" inject="provider:siteService@contentbox"; /** * Constructor */ - AuthorService function init(){ + AuthorService function init() { // init it super.init( entityName = "cbAuthor" ); @@ -40,16 +48,16 @@ component * * @authorId The author id to report on */ - numeric function getTotalPages( required authorId ){ + numeric function getTotalPages( required authorId ) { return executeQuery( - query: " + query = " SELECT count(*) FROM cbContent content join content.creator creator WHERE creator.authorID = :authorId AND content.contentType = 'Page' ", - params: { "authorId" : arguments.authorId }, - unique: true + params = { "authorId": arguments.authorId }, + unique = true ); } @@ -58,16 +66,16 @@ component * * @authorId The author id to report on */ - numeric function getTotalEntries( required authorId ){ + numeric function getTotalEntries( required authorId ) { return executeQuery( - query: " + query = " SELECT count(*) FROM cbContent content join content.creator creator WHERE creator.authorID = :authorId AND content.contentType = 'Entry' ", - params: { "authorId" : arguments.authorId }, - unique: true + params = { "authorId": arguments.authorId }, + unique = true ); } @@ -76,16 +84,16 @@ component * * @authorId The author id to report on */ - numeric function getTotalContentStoreItems( required authorId ){ + numeric function getTotalContentStoreItems( required authorId ) { return executeQuery( - query: " + query = " SELECT count(*) FROM cbContent content join content.creator creator WHERE creator.authorID = :authorId AND content.contentType = 'ContentStore' ", - params: { "authorId" : arguments.authorId }, - unique: true + params = { "authorId": arguments.authorId }, + unique = true ); } @@ -94,32 +102,32 @@ component * * @authorId The author id to report on */ - numeric function getTotalContent( required authorId ){ + numeric function getTotalContent( required authorId ) { return executeQuery( - query: " + query = " SELECT count(*) FROM cbContent content join content.creator creator WHERE creator.authorID = :authorId ", - params: { "authorId" : arguments.authorId }, - unique: true + params = { "authorId": arguments.authorId }, + unique = true ); } /** * Get a status report of authors in the system. */ - function getStatusReport(){ - var c = newCriteria(); + function getStatusReport() { + var c = newCriteria(); var results = { - "active" : 0, - "deactivated" : 0, - "2FactorAuthEnabled" : 0, - "2FactorAuthDisabled" : 0 + "active" : 0, + "deactivated" : 0, + "2FactorAuthEnabled" : 0, + "2FactorAuthDisabled": 0 }; var statusReport = c - .withProjections( count: "isActive:authors", groupProperty: "isActive" ) + .withProjections( count = "isActive:authors", groupProperty = "isActive" ) .asStruct() .list(); @@ -132,7 +140,10 @@ component } var twoFactorAuthReport = c - .withProjections( count: "is2FactorAuth:authors", groupProperty: "is2FactorAuth" ) + .withProjections( + count = "is2FactorAuth:authors", + groupProperty = "is2FactorAuth" + ) .asStruct() .list(); @@ -152,7 +163,7 @@ component * * @author The author to delete */ - AuthorService function delete( required author ){ + AuthorService function delete( required author ) { transaction { // Clear out relationships arguments.author.clearPermissions(); @@ -172,7 +183,7 @@ component * * @return true if they match */ - boolean function isSameHash( required incoming, required target ){ + boolean function isSameHash( required incoming, required target ) { return variables.bcrypt.checkPassword( arguments.incoming, arguments.target ); } @@ -183,7 +194,7 @@ component * * @return The created author */ - Author function createNewAuthor( required author ){ + Author function createNewAuthor( required author ) { transaction { // Save it this.save( arguments.author ); @@ -192,9 +203,9 @@ component var mailResults = sendNewUserEmail( arguments.author ); if ( mailResults.error ) { variables.logger.error( - "Error sending author created email for #arguments.author.getFullName()#", - mailResults.messages - ); + "Error sending author created email for #arguments.author.getFullName()#", + mailResults.messages + ); } } @@ -209,9 +220,9 @@ component * * @return Author */ - Author function save( required author, boolean passwordChange = false ){ + Author function save( required author, boolean passwordChange = false ) { // bcrypt password if new author - if ( !arguments.author.isLoaded() OR arguments.passwordChange ) { + if ( !arguments.author.isLoaded() || arguments.passwordChange ) { // bcrypt the incoming password arguments.author.setPassword( variables.bcrypt.hashPassword( arguments.author.getPassword() ) ); } @@ -239,58 +250,60 @@ component string searchTerm = "", string isActive, string role, - numeric max = 0, - numeric offset = 0, - boolean asQuery = false, - string sortOrder = "lastName", + numeric max = 0, + numeric offset = 0, + boolean asQuery = false, + string sortOrder = "lastName", string permissionGroups, string twoFactorAuth - ){ - var results = { "count" : 0, "authors" : [] }; - var c = newCriteria(); + ) { + var results = { "count": 0, "authors": [] }; + var c = newCriteria(); // Search if ( len( arguments.searchTerm ) ) { c.$or( - c.restrictions.like( "firstName", "%#arguments.searchTerm#%" ), - c.restrictions.like( "lastName", "%#arguments.searchTerm#%" ), - c.restrictions.like( "email", "%#arguments.searchTerm#%" ) - ); + c.restrictions.like( "firstName", "%#arguments.searchTerm#%" ), + c.restrictions.like( "lastName", "%#arguments.searchTerm#%" ), + c.restrictions.like( "email", "%#arguments.searchTerm#%" ) + ); } // isActive filter - if ( structKeyExists( arguments, "isActive" ) AND arguments.isActive NEQ "any" ) { + if ( structKeyExists( arguments, "isActive" ) && arguments.isActive NEQ "any" ) { c.isEq( "isActive", javacast( "boolean", arguments.isActive ) ); } // twoFactorAuth filter - if ( structKeyExists( arguments, "twoFactorAuth" ) AND arguments.twoFactorAuth NEQ "any" ) { - c.isEq( "is2FactorAuth", javacast( "boolean", arguments.twoFactorAuth ) ); + if ( structKeyExists( arguments, "twoFactorAuth" ) && arguments.twoFactorAuth NEQ "any" ) { + c.isEq( + "is2FactorAuth", + javacast( "boolean", arguments.twoFactorAuth ) + ); } // role filter - if ( structKeyExists( arguments, "role" ) AND arguments.role NEQ "any" ) { + if ( structKeyExists( arguments, "role" ) && arguments.role NEQ "any" ) { c.createAlias( "role", "role" ).isEq( "role.roleID", arguments.role ); } // permission groups filter - if ( structKeyExists( arguments, "permissionGroups" ) AND arguments.permissionGroups NEQ "any" ) { - c.createAlias( "permissionGroups", "permissionGroups" ) - .isIn( "permissionGroups.permissionGroupID", listToArray( arguments.permissionGroups ) ); + if ( structKeyExists( arguments, "permissionGroups" ) && arguments.permissionGroups NEQ "any" ) { + c.createAlias( "permissionGroups", "permissionGroups" ).isIn( + "permissionGroups.permissionGroupID", + listToArray( arguments.permissionGroups ) + ); } // run criteria query and projections count - results.count = c.count( "authorID" ); - results.authors = c - .resultTransformer( c.DISTINCT_ROOT_ENTITY ) - .list( + results.count = c.count( "authorID" ); + results.authors = c.resultTransformer( c.DISTINCT_ROOT_ENTITY ).list( offset = arguments.offset, max = arguments.max, sortOrder = arguments.sortOrder, asQuery = arguments.asQuery ); - return results; } @@ -301,7 +314,7 @@ component * * @throws EntityNotFound */ - Author function retrieveUserByUsername( required username ){ + Author function retrieveUserByUsername( required username ) { var oAuthor = newCriteria() .isEq( "username", arguments.username ) .isTrue( "isActive" ) @@ -324,7 +337,7 @@ component * * @throws EntityNotFound */ - Author function retrieveUserById( required id ){ + Author function retrieveUserById( required id ) { var oAuthor = newCriteria() .isEq( "authorID", arguments.id ) .isTrue( "isActive" ) @@ -332,7 +345,10 @@ component .get(); if ( isNull( oAuthor ) ) { - throw( type = "EntityNotFound", message = "Author not found with id (#encodeForHTML( arguments.id )#)" ); + throw( + type = "EntityNotFound", + message = "Author not found with id (#encodeForHTML( arguments.id )#)" + ); } return oAuthor; } @@ -342,8 +358,8 @@ component * * @username The username to check if it exists already */ - boolean function usernameFound( required username ){ - var args = { "username" : arguments.username }; + boolean function usernameFound( required username ) { + var args = { "username": arguments.username }; return ( countWhere( argumentCollection = args ) GT 0 ); } @@ -352,20 +368,22 @@ component * * @email The email to check if it exists already */ - boolean function emailFound( required email ){ - var args = { "email" : arguments.email }; + boolean function emailFound( required email ) { + var args = { "email": arguments.email }; return ( countWhere( argumentCollection = args ) GT 0 ); } /** * Get all data prepared for export */ - array function getAllForExport(){ - return getAll().map( function( thisItem ){ - return arguments.thisItem.getMemento( - includes: "permissions,permissionGroups,isPasswordReset,is2FactorAuth" + array function getAllForExport() { + return getAll().map( + function( thisItem ) { + return arguments.thisItem.getMemento( + includes = "permissions,permissionGroups,isPasswordReset,is2FactorAuth" + ); + } ); - } ); } /** @@ -378,14 +396,17 @@ component * * @throws InvalidImportFormat */ - string function importFromFile( required importFile, boolean override = false ){ - var data = fileRead( arguments.importFile ); + string function importFromFile( required importFile, boolean override = false ) { + var data = fileRead( arguments.importFile ); var importLog = createObject( "java", "java.lang.StringBuilder" ).init( - "Starting import with override = #arguments.override#...
    " - ); + "Starting import with override = #arguments.override#...
    " + ); if ( !isJSON( data ) ) { - throw( message = "Cannot import file as the contents is not JSON", type = "InvalidImportFormat" ); + throw( + message = "Cannot import file as the contents is not JSON", + type = "InvalidImportFormat" + ); } // deserialize packet: Should be array of { settingID, name, value } @@ -411,12 +432,12 @@ component required importData, boolean override = false, importLog - ){ + ) { var allUsers = []; // if struct, inflate into an array if ( isStruct( arguments.importData ) ) { - arguments.importData = [ arguments.importData ]; + arguments.importData = [ arguments.importData]; } transaction { @@ -424,15 +445,15 @@ component for ( var thisUser in arguments.importData ) { // Get new or persisted var oUser = this.findByUsername( thisUser.username ); - oUser = ( isNull( oUser ) ? new () : oUser ); + oUser = ( isNull( oUser ) ? new() : oUser ); // populate content from data getBeanPopulator().populateFromStruct( - target = oUser, - memento = thisUser, - exclude = "role,authorID,permissions,permissionGroups", - composeRelationships = false - ); + target = oUser, + memento = thisUser, + exclude = "role,authorID,permissions,permissionGroups", + composeRelationships = false + ); // A-LA-CARTE PERMISSIONS if ( arrayLen( thisUser.permissions ) ) { @@ -440,12 +461,14 @@ component var allPermissions = []; for ( var thisPermission in thisUser.permissions ) { var oPerm = variables.permissionService.findByPermission( thisPermission.permission ); - oPerm = ( - isNull( oPerm ) ? getBeanPopulator().populateFromStruct( - target = variables.permissionService.new(), - memento = thisPermission, - exclude = "permissionID" - ) : oPerm + oPerm = ( + isNull( oPerm ) + ? getBeanPopulator().populateFromStruct( + target = variables.permissionService.new(), + memento = thisPermission, + exclude = "permissionID" + ) + : oPerm ); // save oPerm if new only if ( !oPerm.isLoaded() ) { @@ -461,12 +484,14 @@ component // Create group permissions that don't exist first for ( var thisGroup in thisUser.permissionGroups ) { var oGroup = variables.permissionGroupService.findByName( thisGroup.name ); - oGroup = ( - isNull( oGroup ) ? getBeanPopulator().populateFromStruct( - target = variables.permissionGroupService.new(), - memento = thisGroup, - exclude = "permissionGroupID,permissions" - ) : oGroup + oGroup = ( + isNull( oGroup ) + ? getBeanPopulator().populateFromStruct( + target = variables.permissionGroupService.new(), + memento = thisGroup, + exclude = "permissionGroupID,permissions" + ) + : oGroup ); // save oGroup if new only if ( !oGroup.isLoaded() ) { @@ -483,8 +508,8 @@ component arguments.importLog.append( "User role found and linked: #thisUser.role.role#
    " ); } else { throw( - message: "The role to import (#encodeForHTML( thisUser.role.role )#) does not exist in the system. Create it or import it first.", - type : "RoleNotFoundException" + message = "The role to import (#encodeForHTML( thisUser.role.role )#) does not exist in the system. Create it or import it first.", + type = "RoleNotFoundException" ); } @@ -492,7 +517,7 @@ component if ( !oUser.isLoaded() ) { arguments.importLog.append( "New user imported: #thisUser.username#
    " ); arrayAppend( allUsers, oUser ); - } else if ( oUser.isLoaded() and arguments.override ) { + } else if ( oUser.isLoaded() && arguments.override ) { arguments.importLog.append( "Persisted user overriden: #thisUser.username#
    " ); arrayAppend( allUsers, oUser ); } else { @@ -507,8 +532,8 @@ component arguments.importLog.append( "Saved all imported and overriden users!" ); } else { arguments.importLog.append( - "No users imported as none where found or able to be overriden from the import file." - ); + "No users imported as none where found or able to be overriden from the import file." + ); } } // end of transaction @@ -523,49 +548,55 @@ component * * @return struct of { error:boolean, messages:array } */ - struct function sendNewUserEmail( required Author author ){ - var token = variables.securityService.generateResetToken( arguments.author ); - var settings = variables.settingService.getAllSettings(); + struct function sendNewUserEmail( required Author author ) { + var token = variables.securityService.generateResetToken( arguments.author ); + var settings = variables.settingService.getAllSettings(); var defaultSite = variables.siteService.getDefaultSite(); - var adminUrl = variables.requestService.getContext().buildLink( to: "/cbadmin", ssl: settings.cb_admin_ssl ); + var adminUrl = variables + .requestService + .getContext() + .buildLink( to = "/cbadmin", ssl = settings.cb_admin_ssl ); // get mail payload var bodyTokens = { - name : arguments.author.getFullName(), - email : arguments.author.getEmail(), - username : arguments.author.getUsername(), - linkTimeout : settings.cb_security_password_reset_expiration, - linkToken : adminUrl & "/security/verifyReset?token=#token#", - resetLink : adminUrl & "/security/lostPassword", - siteName : defaultSite.getName(), - issuedBy : "", - issuedEmail : "" + name : arguments.author.getFullName(), + email : arguments.author.getEmail(), + username : arguments.author.getUsername(), + linkTimeout: settings.cb_security_password_reset_expiration, + linkToken : adminUrl & "/security/verifyReset?token=#token#", + resetLink : adminUrl & "/security/lostPassword", + siteName : defaultSite.getName(), + issuedBy : "", + issuedEmail: "" }; // Build email out var mail = variables.mailservice.newMail( - to = arguments.author.getEmail(), - from = settings.cb_site_outgoingEmail, - subject = "#defaultSite.getName()# Account was created for you", - bodyTokens = bodyTokens, - type = "html", - server = settings.cb_site_mail_server, - username = settings.cb_site_mail_username, - password = settings.cb_site_mail_password, - port = settings.cb_site_mail_smtp, - useTLS = settings.cb_site_mail_tls, - useSSL = settings.cb_site_mail_ssl - ); + to = arguments.author.getEmail(), + from = settings.cb_site_outgoingEmail, + subject = "#defaultSite.getName()# Account was created for you", + bodyTokens = bodyTokens, + type = "html", + server = settings.cb_site_mail_server, + username = settings.cb_site_mail_username, + password = settings.cb_site_mail_password, + port = settings.cb_site_mail_smtp, + useTLS = settings.cb_site_mail_tls, + useSSL = settings.cb_site_mail_ssl + ); mail.setBody( - variables.renderer.layout( - layout = "/contentbox/email_templates/layouts/email", - view = "contentbox/email_templates/author_welcome" - ) - ); + variables.renderer.layout( + layout = "/contentbox/email_templates/layouts/email", + view = "contentbox/email_templates/author_welcome" + ) + ); // send it out - return variables.mailService.send( mail ).getResults(); + return variables + .mailService + .send( mail ) + .getResults(); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/security/ISecurityService.cfc b/modules/contentbox/models/security/ISecurityService.cfc index 6791fe312c..4ed40baf19 100755 --- a/modules/contentbox/models/security/ISecurityService.cfc +++ b/modules/contentbox/models/security/ISecurityService.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -81,5 +81,4 @@ interface { * Checks Whether a content entry or page is protected and user has credentials for it */ boolean function isContentViewable( required content ); - -} +} \ No newline at end of file diff --git a/modules/contentbox/models/security/LoginAttempt.cfc b/modules/contentbox/models/security/LoginAttempt.cfc index df6c119b4b..b7ea9448df 100644 --- a/modules/contentbox/models/security/LoginAttempt.cfc +++ b/modules/contentbox/models/security/LoginAttempt.cfc @@ -13,91 +13,87 @@ component cachename ="loginAttempt" cacheuse ="read-write" { - - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ /** * Primary key */ property - name ="loginAttemptsID" - column ="loginAttemptsID" + name="loginAttemptsID" + column="loginAttemptsID" fieldtype="id" generator="uuid" - length ="36" - ormtype ="string" - update ="false"; + length="36" + ormtype="string" + update="false"; /** * The username attempt value */ property - name ="value" - column ="value" + name="value" + column="value" notnull="true" default="" - length ="255" - index ="idx_values"; + length="255" + index="idx_values"; + /** * How many attempts in the system */ property - name ="attempts" - column ="attempts" + name="attempts" + column="attempts" ormtype="integer" notnull="true" default="0"; + /** * Tracks the last successful login IP address */ property - name ="lastLoginSuccessIP" - column ="lastLoginSuccessIP" + name="lastLoginSuccessIP" + column="lastLoginSuccessIP" notnull="false" - length ="100"; + length="100"; + /** * Verifies if tracking is blocked or not */ property - name ="isBlocked" - column ="isBlocked" + name="isBlocked" + column="isBlocked" persistent="false" - default ="false" - type ="boolean"; - - /* ********************************************************************* - ** PK+CONSTRAINTS - ********************************************************************* */ + default="false" + type="boolean"; + /********************************************************************** + * ** PK+CONSTRAINTS + **********************************************************************/ this.pk = "loginAttemptsID"; this.memento = { - defaultIncludes : [ - "value", - "attempts", - "lastLoginSuccessIP", - "isBlocked" - ], - defaultExcludes : [ "" ] + defaultIncludes: [ "value", "attempts", "lastLoginSuccessIP", "isBlocked"], + defaultExcludes: [ ""] }; - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ /** * Constructor */ - function init(){ + function init() { variables.createdDate = now(); - variables.attempts = 0; - variables.isBlocked = false; + variables.attempts = 0; + variables.isBlocked = false; super.init(); return this; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/security/LoginTracker.cfc b/modules/contentbox/models/security/LoginTracker.cfc index 8ba2f8b93e..7651355002 100644 --- a/modules/contentbox/models/security/LoginTracker.cfc +++ b/modules/contentbox/models/security/LoginTracker.cfc @@ -6,19 +6,23 @@ * Listens to login attempts to keep track of them via the Login Tracker System */ component extends="coldbox.system.Interceptor" { - // DI property name="settingService" inject="id:settingService@contentbox"; + property name="securityService" inject="id:securityService@contentbox"; + property name="loginTrackerService" inject="id:loginTrackerService@contentbox"; + property name="cb" inject="cbhelper@contentbox"; + property name="systemUtil" inject="SystemUtil@contentbox"; + property name="messagebox" inject="messagebox@cbMessagebox"; /** * Configure interceptor */ - function configure(){ + function configure() { return this; } @@ -26,7 +30,7 @@ component extends="coldbox.system.Interceptor" { * Before login check if user has been blocked. It will verify login attempts * by username and IP address and block accordingly. */ - function cbadmin_preLogin( event, data, buffer ){ + function cbadmin_preLogin( event, data, buffer ) { // if disabled, we do not track logins if ( !settingService.getSetting( "cb_security_login_blocker" ) ) { return; @@ -35,28 +39,28 @@ component extends="coldbox.system.Interceptor" { loginTrackerService.reset(); // prepare collections - var prc = event.getCollection( private = true ); - var realIP = variables.securityService.getRealIP(); + var prc = event.getCollection( private = true ); + var realIP = variables.securityService.getRealIP(); var realUsername = event.getValue( "username", "" ); // Try to find by username or IPs being blocked - var aBlockIPs = loginTrackerService.findAllByValue( realIP ); + var aBlockIPs = loginTrackerService.findAllByValue( realIP ); var aBlockUsernames = loginTrackerService.findAllByValue( realUsername ); - prc.oBlockByIP = ( arrayLen( aBlockIps ) ? aBlockIps[ 1 ] : loginTrackerService.new() ); + prc.oBlockByIP = ( arrayLen( aBlockIps ) ? aBlockIps[ 1 ] : loginTrackerService.new() ); prc.oBlockByUsername = ( arrayLen( aBlockUsernames ) ? aBlockUsernames[ 1 ] : loginTrackerService.new() ); // do checks to prevent login var isBlocked = false; // which reason? - var byIP = false; + var byIP = false; // do checks by username and IP - if ( !isNull( prc.oBlockByUsername ) and loginTrackerService.isBlocked( prc.oBlockByUsername ) ) { + if ( !isNull( prc.oBlockByUsername ) && loginTrackerService.isBlocked( prc.oBlockByUsername ) ) { isBlocked = true; } - if ( !isNull( prc.oBlockByIP ) and loginTrackerService.isBlocked( prc.oBlockByIP ) ) { + if ( !isNull( prc.oBlockByIP ) && loginTrackerService.isBlocked( prc.oBlockByIP ) ) { isBlocked = true; - byIP = true; + byIP = true; } // If blocked, relocate @@ -67,7 +71,9 @@ component extends="coldbox.system.Interceptor" { messagebox.warn( cb.r( "messages.user_blocked@security" ) ); } // Log it - log.warn( "Request blocked (#realIP#;#realUsername#) via login tracker" ); + log.warn( + "Request blocked (#realIP#;#realUsername#) via login tracker" + ); // Relocate relocate( "#prc.cbAdminEntryPoint#.security.login" ); } @@ -76,21 +82,23 @@ component extends="coldbox.system.Interceptor" { /** * Listen to successful logins */ - function cbadmin_onLogin( event, data, buffer ){ + function cbadmin_onLogin( event, data, buffer ) { // if disabled, we do not track logins if ( !settingService.getSetting( "cb_security_login_blocker" ) ) { return; } // get prc - var prc = event.getCollection( private = true ); + var prc = event.getCollection( private = true ); // get logged in user - var oUser = securityService.getAuthorSession(); + var oUser = securityService.getAuthorSession(); // Build entry to log - var oEntry = loginTrackerService.new( { - lastLoginSuccessIP : variables.securityService.getRealIP(), - attempts : 0, - value : oUser.getUsername() - } ); + var oEntry = loginTrackerService.new( + { + lastLoginSuccessIP: variables.securityService.getRealIP(), + attempts : 0, + value : oUser.getUsername() + } + ); // If blocked username get's it right, then log it and clear attempts if ( !isNull( prc.oBlockByUsername ) ) { @@ -112,21 +120,21 @@ component extends="coldbox.system.Interceptor" { * so we can verify later if they will be blocked by username or ip misuses * the blockByIp and blockByUsername entities are prepared on pre-login */ - void function cbadmin_onBadLogin( event, data, buffer ){ + void function cbadmin_onBadLogin( event, data, buffer ) { // if disabled, we do not track logins if ( !settingService.getSetting( "cb_security_login_blocker" ) ) { return; } // prepare collections - var prc = event.getCollection( private = true ); - var realIP = variables.securityService.getRealIP(); + var prc = event.getCollection( private = true ); + var realIP = variables.securityService.getRealIP(); var realUsername = event.getValue( "username", "" ); // make or update entry for IP if ( !isNull( prc.oBlockByIP ) ) { prc.oBlockByIP.setAttempts( prc.oBlockByIP.getAttempts() + 1 ); } else { - prc.oBlockByIP = loginTrackerService.new( { value : realIP, attempts : 1 } ); + prc.oBlockByIP = loginTrackerService.new( { value: realIP, attempts: 1 } ); } // Update date + Log it by ip prc.oBlockByIP.setCreatedDate( now() ); @@ -136,11 +144,11 @@ component extends="coldbox.system.Interceptor" { if ( !isNull( prc.oBlockByUsername ) ) { prc.oBlockByUsername.setAttempts( prc.oBlockByUsername.getAttempts() + 1 ); } else { - prc.oBlockByUsername = loginTrackerService.new( { value : realUsername, attempts : 1 } ); + prc.oBlockByUsername = loginTrackerService.new( { value: realUsername, attempts: 1 } ); } // Update date + Log it by ip prc.oBlockByUsername.setCreatedDate( now() ); loginTrackerService.save( prc.oBlockByUsername ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/security/LoginTrackerService.cfc b/modules/contentbox/models/security/LoginTrackerService.cfc index 7f1953b494..137c00692a 100644 --- a/modules/contentbox/models/security/LoginTrackerService.cfc +++ b/modules/contentbox/models/security/LoginTrackerService.cfc @@ -6,16 +6,17 @@ * This Service tracks logins into the ContentBox System */ component extends="cborm.models.VirtualEntityService" singleton { - // DI property name="settingService" inject="id:settingService@contentbox"; + property name="cb" inject="cbhelper@contentbox"; + property name="log" inject="logbox:logger:{this}"; /** * Constructor */ - function init(){ + function init() { // init it super.init( entityName = "cbLoginAttempt" ); return this; @@ -28,13 +29,20 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @return If the attempt was blocked or not */ - boolean function isBlocked( LoginAttempt attempt ){ - var max_attempts = variables.settingService.getSetting( "cb_security_max_attempts" ); + boolean function isBlocked( LoginAttempt attempt ) { + var max_attempts = variables.settingService.getSetting( "cb_security_max_attempts" ); var max_blockTime = variables.settingService.getSetting( "cb_security_blocktime" ); if ( - arguments.attempt.getAttempts() gte max_attempts AND - ( dateDiff( "n", arguments.attempt.getCreatedDate(), now() ) lte max_blockTime ) + arguments.attempt.getAttempts() GTE max_attempts && + ( + dateDiff( + "n", + arguments.attempt.getCreatedDate(), + now() + ) LTE + max_blockTime + ) ) { return true; } @@ -47,7 +55,7 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @sortOrder The sorting columns. */ - public array function getAll( sortOrder = "attempts" ){ + public array function getAll( sortOrder = "attempts" ) { var allEntries = list( sortOrder = arguments.sortOrder ); for ( var e in allEntries ) { @@ -64,10 +72,8 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @max How many to retrieve */ - function getLastLogins( required numeric max ){ - return newCriteria() - .isNotNull( "lastLoginSuccessIP" ) - .list( + function getLastLogins( required numeric max ) { + return newCriteria().isNotNull( "lastLoginSuccessIP" ).list( asQuery = false, max = arguments.max, sortOrder = "createdDate DESC" @@ -77,7 +83,7 @@ component extends="cborm.models.VirtualEntityService" singleton { /** * Truncate the entire auth logs */ - LoginTrackerService function truncate(){ + LoginTrackerService function truncate() { queryExecute( "TRUNCATE TABLE cb_loginAttempts" ); return this; } @@ -86,22 +92,25 @@ component extends="cborm.models.VirtualEntityService" singleton { * Rotate auth logs * Usually called by the {@code LoginTracker} Interceptor asynchronously */ - LoginTrackerService function rotate(){ + LoginTrackerService function rotate() { // if disabled, we do not track logins if ( !settingService.getSetting( "cb_security_login_blocker" ) ) { - log.debug( "Rotation not enabled since the security login blocker is disabled" ); + log.debug( + "Rotation not enabled since the security login blocker is disabled" + ); return this; } - var maxLogs = variables.settingService.getSetting( "cb_security_max_auth_logs" ); - var maxLogs = 2; + var maxLogs = variables.settingService.getSetting( "cb_security_max_auth_logs" ); + var maxLogs = 2; var totalLogs = count(); // only if we have a max logs and we have gone above max logs, let's truncate if ( len( maxLogs ) && isNumeric( maxLogs ) && totalLogs > maxLogs ) { - var aToDelete = newCriteria() - .withProjections( property = "loginAttemptsID" ) - .list( max = ( totalLogs - maxLogs ), sortOrder = "createdDate ASC" ); + var aToDelete = newCriteria().withProjections( property = "loginAttemptsID" ).list( + max = ( totalLogs - maxLogs ), + sortOrder = "createdDate ASC" + ); var hql = " DELETE FROM cbLoginAttempt @@ -110,9 +119,9 @@ component extends="cborm.models.VirtualEntityService" singleton { // run it var results = executeQuery( - query : hql, - params : { "idsToDelete" : aToDelete }, - asQuery: false + query = hql, + params = { "idsToDelete": aToDelete }, + asQuery = false ); // log it @@ -127,7 +136,7 @@ component extends="cborm.models.VirtualEntityService" singleton { /** * Reset login attempts if the time limit is reached */ - LoginTrackerService function reset(){ + LoginTrackerService function reset() { var limit = dateAdd( "n", variables.settingService.getSetting( "cb_security_blocktime" ) * -1, @@ -141,12 +150,16 @@ component extends="cborm.models.VirtualEntityService" singleton { WHERE createdDate <= :limit "; - var params = { "limit" : limit }; + var params = { "limit": limit }; // run it - executeQuery( query = hql, params = params, asQuery = false ); + executeQuery( + query = hql, + params = params, + asQuery = false + ); return this; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/security/Permission.cfc b/modules/contentbox/models/security/Permission.cfc index 78e05849c4..fa48fc0759 100644 --- a/modules/contentbox/models/security/Permission.cfc +++ b/modules/contentbox/models/security/Permission.cfc @@ -13,86 +13,84 @@ component cachename ="cbPermission" cacheuse ="read-write" { - - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="permissionID" - column ="permissionID" + name="permissionID" + column="permissionID" fieldtype="id" generator="uuid" - length ="36" - ormtype ="string" - update ="false"; + length="36" + ormtype="string" + update="false"; property - name ="permission" - column ="permission" + name="permission" + column="permission" ormtype="string" notnull="true" - length ="255" - unique ="true" + length="255" + unique="true" default="" - index ="idx_permissionName"; + index="idx_permissionName"; property - name ="description" - column ="description" + name="description" + column="description" ormtype="string" notnull="false" default="" - length ="500"; + length="500"; - /* ********************************************************************* - ** CALCULATED FIELDS - ********************************************************************* */ + /********************************************************************** + * ** CALCULATED FIELDS + **********************************************************************/ property - name ="numberOfPermissionGroups" + name="numberOfPermissionGroups" formula="select count(*) from cb_groupPermissions as gp where gp.FK_permissionID=permissionID"; property - name ="numberOfRoles" + name="numberOfRoles" formula="select count(*) from cb_rolePermissions as rolePermissions where rolePermissions.FK_permissionID=permissionID"; property - name ="numberOfGroups" + name="numberOfGroups" formula="select count(*) from cb_groupPermissions as groupPermissions where groupPermissions.FK_permissionID=permissionID"; - - /* ********************************************************************* - ** PK + CONSTRAINTS + MEMENTO - ********************************************************************* */ + /********************************************************************** + * ** PK + CONSTRAINTS + MEMENTO + **********************************************************************/ this.pk = "permissionID"; this.memento = { - defaultIncludes : [ "permission", "description" ], - defaultExcludes : [ "" ] + defaultIncludes: [ "permission", "description"], + defaultExcludes: [ ""] }; this.constraints = { - "permission" : { - required : true, - size : "1..255", - validator : "UniqueValidator@cborm" + "permission": { + required : true, + size : "1..255", + validator: "UniqueValidator@cborm" }, - "description" : { required : false, size : "1..500" } + "description": { required: false, size: "1..500" } }; - /* ********************************************************************* - ** PUBLIC FUNCITONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCITONS + **********************************************************************/ /** * Constructor */ - function init(){ + function init() { super.init(); return this; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/security/PermissionGroup.cfc b/modules/contentbox/models/security/PermissionGroup.cfc index 73e4e8c42d..3a28b94d75 100644 --- a/modules/contentbox/models/security/PermissionGroup.cfc +++ b/modules/contentbox/models/security/PermissionGroup.cfc @@ -13,123 +13,119 @@ component cachename ="cbPermissionGroup" cacheuse ="read-write" { + /********************************************************************** + * ** DI + **********************************************************************/ - /* ********************************************************************* - ** DI - ********************************************************************* */ - - - - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="permissionGroupID" - column ="permissionGroupID" + name="permissionGroupID" + column="permissionGroupID" fieldtype="id" generator="uuid" - length ="36" - update ="false"; + length="36" + update="false"; property - name ="name" - column ="name" + name="name" + column="name" ormtype="string" notnull="true" - length ="255" - unique ="true" + length="255" + unique="true" default="" - index ="idx_permissionGroupName"; + index="idx_permissionGroupName"; property - name ="description" - column ="description" + name="description" + column="description" ormtype="string" notnull="false" default="" - length ="500"; + length="500"; - /* ********************************************************************* - ** RELATIONSHIPS - ********************************************************************* */ + /********************************************************************** + * ** RELATIONSHIPS + **********************************************************************/ // M2M -> Permissions property - name ="permissions" - fieldtype ="many-to-many" - type ="array" - lazy ="true" - orderby ="permission" - cascade ="save-update" - cacheuse ="read-write" - cfc ="contentbox.models.security.Permission" - fkcolumn ="FK_permissionGroupID" - linktable ="cb_groupPermissions" + name="permissions" + fieldtype="many-to-many" + type="array" + lazy="true" + orderby="permission" + cascade="save-update" + cacheuse="read-write" + cfc="contentbox.models.security.Permission" + fkcolumn="FK_permissionGroupID" + linktable="cb_groupPermissions" inversejoincolumn="FK_permissionID"; // M2M -> Authors property - name ="authors" - singularName ="author" - fieldtype ="many-to-many" - type ="array" - lazy ="true" - cacheuse ="read-write" - cfc ="contentbox.models.security.Author" - fkcolumn ="FK_permissionGroupID" - linktable ="cb_authorPermissionGroups" + name="authors" + singularName="author" + fieldtype="many-to-many" + type="array" + lazy="true" + cacheuse="read-write" + cfc="contentbox.models.security.Author" + fkcolumn="FK_permissionGroupID" + linktable="cb_authorPermissionGroups" inversejoincolumn="FK_authorID"; - /* ********************************************************************* - ** CALCULATED FIELDS - ********************************************************************* */ + /********************************************************************** + * ** CALCULATED FIELDS + **********************************************************************/ property - name ="numberOfPermissions" + name="numberOfPermissions" formula="select count(*) from cb_groupPermissions as groupPermissions where groupPermissions.FK_permissionGroupID = permissionGroupID"; property - name ="numberOfAuthors" + name="numberOfAuthors" formula="select count(*) from cb_authorPermissionGroups as pg where pg.FK_permissionGroupID = permissionGroupID"; - /* ********************************************************************* - ** NON PERSISTED PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** NON PERSISTED PROPERTIES + **********************************************************************/ property name="permissionList" persistent="false"; - - /* ********************************************************************* - ** PK + CONSTRAINTS + MEMENTO - ********************************************************************* */ + /********************************************************************** + * ** PK + CONSTRAINTS + MEMENTO + **********************************************************************/ this.pk = "permissionGroupID"; this.memento = { - defaultIncludes : [ "*" ], - defaultExcludes : [ "authors" ] + defaultIncludes: [ "*"], + defaultExcludes: [ "authors"] }; this.constraints = { - "name" : { - required : true, - size : "1..255", - validator : "UniqueValidator@cborm" + "name": { + required : true, + size : "1..255", + validator: "UniqueValidator@cborm" }, - "description" : { required : false, size : "1..500" } + "description": { required: false, size: "1..500" } }; - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ /** * Constructor */ - function init(){ - variables.permissions = []; - variables.authors = []; + function init() { + variables.permissions = []; + variables.authors = []; variables.permissionList = []; super.init(); @@ -141,9 +137,9 @@ component * * @permission One or a list of permissions to verify */ - boolean function hasPermission( required permission ){ + boolean function hasPermission( required permission ) { // cache deconstructed permissions in case it's called many times during a request. - if ( !arrayLen( variables.permissionList ) AND hasPermissions() ) { + if ( !arrayLen( variables.permissionList ) && hasPermissions() ) { variables.permissionList = arrayReduce( getPermissions(), ( result, item ) => { @@ -154,16 +150,16 @@ component } // verify - return arrayWrap( arguments.permission ) - .filter( ( item ) => variables.permissionList.findNoCase( arguments.item ) ) - .len(); + return arrayWrap( arguments.permission ).filter( + ( item ) => variables.permissionList.findNoCase( arguments.item ) + ).len(); } /** * Clear all permissions */ - PermissionGroup function clearPermissions(){ - variables.permissions = []; + PermissionGroup function clearPermissions() { + variables.permissions = []; variables.permissionList = []; return this; } @@ -171,7 +167,7 @@ component /** * Clear all authors */ - PermissionGroup function clearAuthors(){ + PermissionGroup function clearAuthors() { variables.authors = []; return this; } @@ -181,7 +177,7 @@ component * * @permissions The permissions array */ - PermissionGroup function setPermissions( required array permissions ){ + PermissionGroup function setPermissions( required array permissions ) { if ( hasPermissions() ) { variables.permissions.clear(); variables.permissions.addAll( arguments.permissions ); @@ -196,7 +192,7 @@ component * * @authors The permissions array */ - PermissionGroup function setAuthors( required array authors ){ + PermissionGroup function setAuthors( required array authors ) { if ( hasAuthor() ) { variables.authors.clear(); variables.authors.addAll( arguments.authors ); @@ -206,4 +202,4 @@ component return this; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/security/PermissionGroupService.cfc b/modules/contentbox/models/security/PermissionGroupService.cfc index 6a4b6b64d8..ffdcfa2d77 100755 --- a/modules/contentbox/models/security/PermissionGroupService.cfc +++ b/modules/contentbox/models/security/PermissionGroupService.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -6,15 +6,15 @@ * Permission Group Service for contentbox */ component extends="cborm.models.VirtualEntityService" singleton { - // DI property name="permissionService" inject="permissionService@contentbox"; + property name="dateUtil" inject="DateUtil@contentbox"; /** * Constructor */ - PermissionGroupService function init(){ + PermissionGroupService function init() { // init it super.init( entityName = "cbPermissionGroup" ); @@ -24,10 +24,12 @@ component extends="cborm.models.VirtualEntityService" singleton { /** * Get all data prepared for export */ - array function getAllForExport(){ - return getAll().map( function( thisItem ){ - return thisItem.getMemento(); - } ); + array function getAllForExport() { + return getAll().map( + function( thisItem ) { + return thisItem.getMemento(); + } + ); } /** @@ -40,14 +42,17 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @throws InvalidImportFormat */ - string function importFromFile( required importFile, boolean override = false ){ - var data = fileRead( arguments.importFile ); + string function importFromFile( required importFile, boolean override = false ) { + var data = fileRead( arguments.importFile ); var importLog = createObject( "java", "java.lang.StringBuilder" ).init( - "Starting import with override = #arguments.override#...
    " - ); + "Starting import with override = #arguments.override#...
    " + ); if ( !isJSON( data ) ) { - throw( message = "Cannot import file as the contents is not JSON", type = "InvalidImportFormat" ); + throw( + message = "Cannot import file as the contents is not JSON", + type = "InvalidImportFormat" + ); } // deserialize packet: Should be array of { settingID, name, value } @@ -71,12 +76,12 @@ component extends="cborm.models.VirtualEntityService" singleton { required importData, boolean override = false, importLog - ){ + ) { var allGroups = []; // if struct, inflate into an array if ( isStruct( arguments.importData ) ) { - arguments.importData = [ arguments.importData ]; + arguments.importData = [ arguments.importData]; } transaction { @@ -84,15 +89,15 @@ component extends="cborm.models.VirtualEntityService" singleton { for ( var thisGroup in arguments.importData ) { // Get new or persisted var oGroup = this.findByName( thisGroup.name ); - oGroup = ( isNull( oGroup ) ? new () : oGroup ); + oGroup = ( isNull( oGroup ) ? new() : oGroup ); // populate content from data getBeanPopulator().populateFromStruct( - target = oGroup, - memento = thisGroup, - exclude = "permissionGroupID,permissions", - composeRelationships = false - ); + target = oGroup, + memento = thisGroup, + exclude = "permissionGroupID,permissions", + composeRelationships = false + ); // PERMISSIONS if ( arrayLen( thisGroup.permissions ) ) { @@ -100,12 +105,14 @@ component extends="cborm.models.VirtualEntityService" singleton { var allPermissions = []; for ( var thisPermission in thisGroup.permissions ) { var oPerm = variables.permissionService.findByPermission( thisPermission.permission ); - oPerm = ( - isNull( oPerm ) ? getBeanPopulator().populateFromStruct( - target = variables.permissionService.new(), - memento = thisPermission, - exclude = "permissionID" - ) : oPerm + oPerm = ( + isNull( oPerm ) + ? getBeanPopulator().populateFromStruct( + target = variables.permissionService.new(), + memento = thisPermission, + exclude = "permissionID" + ) + : oPerm ); // save oPerm if new only if ( !oPerm.isLoaded() ) { @@ -122,8 +129,10 @@ component extends="cborm.models.VirtualEntityService" singleton { if ( !oGroup.isLoaded() ) { arguments.importLog.append( "New permission group imported: #thisGroup.name#
    " ); arrayAppend( allGroups, oGroup ); - } else if ( oGroup.isLoaded() and arguments.override ) { - arguments.importLog.append( "Persisted permission group overriden: #thisGroup.name#
    " ); + } else if ( oGroup.isLoaded() && arguments.override ) { + arguments.importLog.append( + "Persisted permission group overriden: #thisGroup.name#
    " + ); arrayAppend( allGroups, oGroup ); } else { arguments.importLog.append( "Skipping permission group: #thisGroup.name#
    " ); @@ -137,8 +146,8 @@ component extends="cborm.models.VirtualEntityService" singleton { arguments.importLog.append( "Saved all imported and overriden permission groups!" ); } else { arguments.importLog.append( - "No permission groups imported as none where found or able to be overriden from the import file." - ); + "No permission groups imported as none where found or able to be overriden from the import file." + ); } } // end of transaction @@ -146,4 +155,4 @@ component extends="cborm.models.VirtualEntityService" singleton { return arguments.importLog.toString(); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/security/PermissionService.cfc b/modules/contentbox/models/security/PermissionService.cfc index 404b8b6cb5..8ea643dd75 100755 --- a/modules/contentbox/models/security/PermissionService.cfc +++ b/modules/contentbox/models/security/PermissionService.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -6,14 +6,13 @@ * Permissions service for contentbox */ component extends="cborm.models.VirtualEntityService" singleton { - // DI property name="dateUtil" inject="DateUtil@contentbox"; /** * Constructor */ - PermissionService function init(){ + PermissionService function init() { // init it super.init( entityName = "cbPermission" ); @@ -25,28 +24,28 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @permissionID The permission ID to remove */ - boolean function deletePermission( required permissionID ){ + boolean function deletePermission( required permissionID ) { transaction { // We do SQL deletions as those relationships are not bi-directional queryExecute( "delete from cb_rolePermissions where FK_permissionID = :permissionID", - { "permissionID" : arguments.permissionID } + { "permissionID": arguments.permissionID } ); queryExecute( "delete from cb_authorPermissions where FK_permissionID = :permissionID", - { "permissionID" : arguments.permissionID } + { "permissionID": arguments.permissionID } ); queryExecute( "delete from cb_groupPermissions where FK_permissionID = :permissionID", - { "permissionID" : arguments.permissionID } + { "permissionID": arguments.permissionID } ); queryExecute( "delete from cb_permission where permissionID = :permissionID", - { "permissionID" : arguments.permissionID } + { "permissionID": arguments.permissionID } ); } @@ -58,17 +57,29 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @return Array of struct permission data */ - array function getAllForExport(){ + array function getAllForExport() { return newCriteria() - .withProjections( property = "permissionID,permission,description,createdDate,modifiedDate,isDeleted" ) + .withProjections( + property = "permissionID,permission,description,createdDate,modifiedDate,isDeleted" + ) .asStruct() .list( sortOrder = "permission" ) // output conversions - .map( function( item ){ - item[ "createdDate" ] = variables.dateUtil.toUTC( item[ "createdDate" ], "", "UTC" ); - item[ "modifiedDate" ] = variables.dateUtil.toUTC( item[ "modifiedDate" ], "", "UTC" ); - return item; - } ); + .map( + function( item ) { + item[ "createdDate" ] = variables.dateUtil.toUTC( + item[ "createdDate" ], + "", + "UTC" + ); + item[ "modifiedDate" ] = variables.dateUtil.toUTC( + item[ "modifiedDate" ], + "", + "UTC" + ); + return item; + } + ); } /** @@ -81,14 +92,17 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @throws InvalidImportFormat */ - string function importFromFile( required importFile, boolean override = false ){ - var data = fileRead( arguments.importFile ); + string function importFromFile( required importFile, boolean override = false ) { + var data = fileRead( arguments.importFile ); var importLog = createObject( "java", "java.lang.StringBuilder" ).init( - "Starting import with override = #arguments.override#...
    " - ); + "Starting import with override = #arguments.override#...
    " + ); if ( !isJSON( data ) ) { - throw( message = "Cannot import file as the contents is not JSON", type = "InvalidImportFormat" ); + throw( + message = "Cannot import file as the contents is not JSON", + type = "InvalidImportFormat" + ); } // deserialize packet: Should be array of { settingID, name, value } @@ -114,12 +128,12 @@ component extends="cborm.models.VirtualEntityService" singleton { required importData, boolean override = false, importLog - ){ + ) { var allPermissions = []; // if struct, inflate into an array if ( isStruct( arguments.importData ) ) { - arguments.importData = [ arguments.importData ]; + arguments.importData = [ arguments.importData]; } transaction { @@ -127,21 +141,23 @@ component extends="cborm.models.VirtualEntityService" singleton { for ( var thisPermission in arguments.importData ) { // Get new or persisted var oPermission = this.findByPermission( thisPermission.permission ); - oPermission = ( isNull( oPermission ) ? new () : oPermission ); + oPermission = ( isNull( oPermission ) ? new() : oPermission ); // populate content from data getBeanPopulator().populateFromStruct( - target = oPermission, - memento = thisPermission, - exclude = "permissionID", - composeRelationships = false - ); + target = oPermission, + memento = thisPermission, + exclude = "permissionID", + composeRelationships = false + ); // if new or persisted with override then save. if ( !oPermission.isLoaded() ) { - arguments.importLog.append( "New permission imported: #thisPermission.permission#
    " ); + arguments.importLog.append( + "New permission imported: #thisPermission.permission#
    " + ); arrayAppend( allPermissions, oPermission ); - } else if ( oPermission.isLoaded() and arguments.override ) { + } else if ( oPermission.isLoaded() && arguments.override ) { arguments.importLog.append( "Permission overriden: #thisPermission.permission#
    " ); arrayAppend( allPermissions, oPermission ); } else { @@ -156,8 +172,8 @@ component extends="cborm.models.VirtualEntityService" singleton { arguments.importLog.append( "Saved all imported and overriden permissions!" ); } else { arguments.importLog.append( - "No permissions imported as none where found or able to be overriden from the import file." - ); + "No permissions imported as none where found or able to be overriden from the import file." + ); } } // end of transaction @@ -165,4 +181,4 @@ component extends="cborm.models.VirtualEntityService" singleton { return arguments.importLog.toString(); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/security/RateLimiter.cfc b/modules/contentbox/models/security/RateLimiter.cfc index ea01388ee2..0d3ff6a984 100755 --- a/modules/contentbox/models/security/RateLimiter.cfc +++ b/modules/contentbox/models/security/RateLimiter.cfc @@ -6,26 +6,29 @@ * Limits and prevents DOS attacks */ component extends="coldbox.system.Interceptor" { - // DI property name="settingService" inject="id:settingService@contentbox"; + property name="securityService" inject="id:securityService@contentbox"; + property name="cachebox" inject="Cachebox"; /** * onRequestCapture * fires before any event caching or processing */ - function onRequestCapture( event, data, buffer ){ + function onRequestCapture( event, data, buffer ) { var allSettings = variables.settingService.getAllSettings(); // If turned off, just exist - if ( !structKeyExists( allSettings, "cb_security_rate_limiter" ) || allSettings.cb_security_rate_limiter == false ) { + if ( + !structKeyExists( allSettings, "cb_security_rate_limiter" ) || allSettings.cb_security_rate_limiter == false + ) { return false; } // do we limit bot OR normal requests as well? - if ( !len( cgi.http_cookie ) OR !allSettings.cb_security_rate_limiter_bots_only ) { + if ( !len( cgi.http_cookie ) || !allSettings.cb_security_rate_limiter_bots_only ) { // limit it now. limiter( count = allSettings[ "cb_security_rate_limiter_count" ], @@ -46,15 +49,18 @@ component extends="coldbox.system.Interceptor" { * @event The request context object * @settings The settings structure */ - private function limiter( count, duration, event, settings ){ + private function limiter( count, duration, event, settings ) { // Get real IP address of requester - var realIP = variables.securityService.getRealIP(); - var cache = cachebox.getDefaultCache(); + var realIP = variables.securityService.getRealIP(); + var cache = cachebox.getDefaultCache(); var cacheKey = "limiter" & realIP; - var targetData = cache.getOrSet( cacheKey, function(){ - return { attempts : 0, lastAttempt : now() } - } ); + var targetData = cache.getOrSet( + cacheKey, + function() { + return { attempts: 0, lastAttempt: now() }; + } + ); // on first visit no further processing if ( targetData.attempts == 0 ) { @@ -68,12 +74,22 @@ component extends="coldbox.system.Interceptor" { // log.info( "Within Duration " & dateDiff( "s", targetData.lastAttempt, Now() ) LT arguments.duration ); // Are we executing another request withing our duration in seconds? Ex: Has X seconds passed before last attempt - if ( dateDiff( "s", targetData.lastAttempt, now() ) LT arguments.duration ) { + if ( + dateDiff( + "s", + targetData.lastAttempt, + now() + ) LT + arguments.duration + ) { // Limit by count? if ( targetData.attempts GT arguments.count ) { if ( settings.cb_security_rate_limiter_logging && log.canInfo() ) { // Log it to app logs - log.info( "'limiter invoked for:','#realIP#',#targetData.attempts#,#cgi.request_method#,'#cgi.SCRIPT_NAME#', '#cgi.QUERY_STRING#','#cgi.http_user_agent#','#targetData.lastAttempt#',#listLen( cgi.http_cookie, ";" )#" ); + log.info( + "'limiter invoked for:','#realIP#',#targetData.attempts#,#cgi.request_method#,'#cgi.SCRIPT_NAME#', '#cgi.QUERY_STRING#','#cgi.http_user_agent#','#targetData.lastAttempt#',#listLen( cgi.http_cookie, + ";" )#" + ); } // Log attempt @@ -100,7 +116,8 @@ component extends="coldbox.system.Interceptor" { "all" ) ); - arguments.event + arguments + .event .setHTTPHeader( statusCode = "503" ) .setHTTPHeader( name = "Retry-After", value = arguments.duration ); @@ -116,7 +133,7 @@ component extends="coldbox.system.Interceptor" { } } else { // Reset attempts counter, since we are in the safe zone, just log the last attempt timestamp - targetData.attempts = 0; + targetData.attempts = 0; targetData.lastAttempt = now(); } @@ -124,4 +141,4 @@ component extends="coldbox.system.Interceptor" { return this; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/security/Role.cfc b/modules/contentbox/models/security/Role.cfc index 130edcdef4..3a450446d8 100644 --- a/modules/contentbox/models/security/Role.cfc +++ b/modules/contentbox/models/security/Role.cfc @@ -13,108 +13,108 @@ component cachename ="cbRole" cacheuse ="read-write" { - - /* ********************************************************************* - ** DI - ********************************************************************* */ + /********************************************************************** + * ** DI + **********************************************************************/ property - name ="permissionService" - inject ="provider:permissionService@contentbox" + name="permissionService" + inject="provider:permissionService@contentbox" persistent="false"; - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="roleID" - column ="roleID" + name="roleID" + column="roleID" fieldtype="id" generator="uuid" - length ="36" - ormtype ="string" - update ="false"; + length="36" + ormtype="string" + update="false"; property - name ="role" - column ="role" + name="role" + column="role" ormtype="string" notnull="true" - length ="255" - unique ="true" + length="255" + unique="true" default="" - index ="idx_roleName"; + index="idx_roleName"; property - name ="description" - column ="description" + name="description" + column="description" ormtype="string" notnull="false" default="" - length ="500"; + length="500"; - /* ********************************************************************* - ** RELATIONSHIPS - ********************************************************************* */ + /********************************************************************** + * ** RELATIONSHIPS + **********************************************************************/ // M2M -> Permissions property - name ="permissions" - fieldtype ="many-to-many" - type ="array" - lazy ="true" - orderby ="permission" - cascade ="save-update" - cacheuse ="read-write" - cfc ="contentbox.models.security.Permission" - fkcolumn ="FK_roleID" - linktable ="cb_rolePermissions" + name="permissions" + fieldtype="many-to-many" + type="array" + lazy="true" + orderby="permission" + cascade="save-update" + cacheuse="read-write" + cfc="contentbox.models.security.Permission" + fkcolumn="FK_roleID" + linktable="cb_rolePermissions" inversejoincolumn="FK_permissionID"; - /* ********************************************************************* - ** CALUCLATED FIELDS - ********************************************************************* */ + /********************************************************************** + * ** CALUCLATED FIELDS + **********************************************************************/ property - name ="numberOfPermissions" + name="numberOfPermissions" formula="select count(*) from cb_rolePermissions as rolePermissions where rolePermissions.FK_roleID=roleID"; - property name="numberOfAuthors" formula="select count(*) from cb_author as author where author.FK_roleID=roleID"; + property + name="numberOfAuthors" + formula="select count(*) from cb_author as author where author.FK_roleID=roleID"; - /* ********************************************************************* - ** NON PERSISTED PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** NON PERSISTED PROPERTIES + **********************************************************************/ property name="permissionList" persistent="false"; - - /* ********************************************************************* - ** PK + CONSTRAINTS + MEMENTO - ********************************************************************* */ + /********************************************************************** + * ** PK + CONSTRAINTS + MEMENTO + **********************************************************************/ this.pk = "roleID"; this.memento = { - defaultIncludes : [ "role", "description" ], - defaultExcludes : [ "permissionList" ] + defaultIncludes: [ "role", "description"], + defaultExcludes: [ "permissionList"] }; this.constraints = { - "role" : { - required : true, - size : "1..255", - validator : "UniqueValidator@cborm" + "role": { + required : true, + size : "1..255", + validator: "UniqueValidator@cborm" }, - "description" : { required : false, size : "1..500" } + "description": { required: false, size: "1..500" } }; - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ // Constructor - function init(){ - variables.permissions = []; + function init() { + variables.permissions = []; variables.permissionList = []; super.init(); @@ -124,7 +124,7 @@ component /** * Get the role name, same as getRole() */ - string function getName(){ + string function getName() { return variables.role; } @@ -133,9 +133,9 @@ component * * @permission One or a list of permissions to verify */ - boolean function hasPermission( required permission ){ + boolean function hasPermission( required permission ) { // cache deconstructed permissions in case it's called many times during a request. - if ( !arrayLen( variables.permissionList ) AND hasPermissions() ) { + if ( !arrayLen( variables.permissionList ) && hasPermissions() ) { variables.permissionList = arrayReduce( getPermissions(), ( result, item ) => { @@ -145,16 +145,16 @@ component ); } // verify - return arrayWrap( arguments.permission ) - .filter( ( item ) => variables.permissionList.findNoCase( arguments.item ) ) - .len(); + return arrayWrap( arguments.permission ).filter( + ( item ) => variables.permissionList.findNoCase( arguments.item ) + ).len(); } /** * Clear all permissions */ - Role function clearPermissions(){ - variables.permissions = []; + Role function clearPermissions() { + variables.permissions = []; variables.permissionList = []; return this; } @@ -162,7 +162,7 @@ component /** * Override the setPermissions */ - Role function setPermissions( required array permissions ){ + Role function setPermissions( required array permissions ) { if ( hasPermissions() ) { variables.permissions.clear(); variables.permissions.addAll( arguments.permissions ); @@ -172,4 +172,4 @@ component return this; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/security/RoleService.cfc b/modules/contentbox/models/security/RoleService.cfc index 3e509b0967..b5f9d5809f 100755 --- a/modules/contentbox/models/security/RoleService.cfc +++ b/modules/contentbox/models/security/RoleService.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -6,15 +6,15 @@ * Roles service for contentbox */ component extends="cborm.models.VirtualEntityService" singleton { - // DI property name="permissionService" inject="permissionService@contentbox"; + property name="dateUtil" inject="DateUtil@contentbox"; /** * Constructor */ - RoleService function init(){ + RoleService function init() { // init it super.init( entityName = "cbRole" ); @@ -24,10 +24,12 @@ component extends="cborm.models.VirtualEntityService" singleton { /** * Get all data prepared for export */ - array function getAllForExport(){ - return getAll().map( function( thisItem ){ - return thisItem.getMemento( includes = "permissions" ); - } ); + array function getAllForExport() { + return getAll().map( + function( thisItem ) { + return thisItem.getMemento( includes = "permissions" ); + } + ); } /** @@ -40,14 +42,17 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @throws InvalidImportFormat */ - string function importFromFile( required importFile, boolean override = false ){ - var data = fileRead( arguments.importFile ); + string function importFromFile( required importFile, boolean override = false ) { + var data = fileRead( arguments.importFile ); var importLog = createObject( "java", "java.lang.StringBuilder" ).init( - "Starting import with override = #arguments.override#...
    " - ); + "Starting import with override = #arguments.override#...
    " + ); if ( !isJSON( data ) ) { - throw( message = "Cannot import file as the contents is not JSON", type = "InvalidImportFormat" ); + throw( + message = "Cannot import file as the contents is not JSON", + type = "InvalidImportFormat" + ); } // deserialize packet: Should be array of { settingID, name, value } @@ -73,12 +78,12 @@ component extends="cborm.models.VirtualEntityService" singleton { required importData, boolean override = false, importLog - ){ + ) { var allRoles = []; // if struct, inflate into an array if ( isStruct( arguments.importData ) ) { - arguments.importData = [ arguments.importData ]; + arguments.importData = [ arguments.importData]; } transaction { @@ -86,15 +91,15 @@ component extends="cborm.models.VirtualEntityService" singleton { for ( var thisRole in arguments.importData ) { // Get new or persisted var oRole = this.findByRole( thisRole.role ); - oRole = ( isNull( oRole ) ? new () : oRole ); + oRole = ( isNull( oRole ) ? new() : oRole ); // populate content from data getBeanPopulator().populateFromStruct( - target = oRole, - memento = thisRole, - exclude = "roleID,permissions", - composeRelationships = false - ); + target = oRole, + memento = thisRole, + exclude = "roleID,permissions", + composeRelationships = false + ); // PERMISSIONS if ( arrayLen( thisRole.permissions ) ) { @@ -102,12 +107,14 @@ component extends="cborm.models.VirtualEntityService" singleton { var allPermissions = []; for ( var thisPermission in thisRole.permissions ) { var oPerm = variables.permissionService.findByPermission( thisPermission.permission ); - oPerm = ( - isNull( oPerm ) ? getBeanPopulator().populateFromStruct( - target = variables.permissionService.new(), - memento = thisPermission, - exclude = "permissionID" - ) : oPerm + oPerm = ( + isNull( oPerm ) + ? getBeanPopulator().populateFromStruct( + target = variables.permissionService.new(), + memento = thisPermission, + exclude = "permissionID" + ) + : oPerm ); // save oPerm if new only if ( !oPerm.isLoaded() ) { @@ -124,7 +131,7 @@ component extends="cborm.models.VirtualEntityService" singleton { if ( !oRole.isLoaded() ) { arguments.importLog.append( "New role imported: #thisRole.role#
    " ); arrayAppend( allRoles, oRole ); - } else if ( oRole.isLoaded() and arguments.override ) { + } else if ( oRole.isLoaded() && arguments.override ) { arguments.importLog.append( "Persisted role overriden: #thisRole.role#
    " ); arrayAppend( allRoles, oRole ); } else { @@ -139,8 +146,8 @@ component extends="cborm.models.VirtualEntityService" singleton { arguments.importLog.append( "Saved all imported and overriden roles!" ); } else { arguments.importLog.append( - "No roles imported as none where found or able to be overriden from the import file." - ); + "No roles imported as none where found or able to be overriden from the import file." + ); } } // end transaction @@ -148,4 +155,4 @@ component extends="cborm.models.VirtualEntityService" singleton { return arguments.importLog.toString(); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/security/SecurityRule.cfc b/modules/contentbox/models/security/SecurityRule.cfc index 50c8d2a76e..97401e7c7d 100644 --- a/modules/contentbox/models/security/SecurityRule.cfc +++ b/modules/contentbox/models/security/SecurityRule.cfc @@ -13,151 +13,149 @@ component cachename ="cbSecurityRule" cacheuse ="read-write" { - - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="ruleID" - column ="ruleID" + name="ruleID" + column="ruleID" fieldtype="id" generator="uuid" - length ="36" - ormtype ="string" - update ="false"; + length="36" + ormtype="string" + update="false"; property - name ="whitelist" - column ="whitelist" + name="whitelist" + column="whitelist" ormtype="string" notnull="false" default="" - length ="255"; + length="255"; property - name ="securelist" - column ="securelist" + name="securelist" + column="securelist" ormtype="string" notnull="true" default="" - length ="255"; + length="255"; property - name ="match" - column ="match" - ormtype ="string" - notnull ="false" - default ="event" + name="match" + column="match" + ormtype="string" + notnull="false" + default="event" dbdefault="'event'" - length ="50"; + length="50"; property - name ="roles" - column ="roles" + name="roles" + column="roles" ormtype="string" notnull="false" default="" - length ="255"; + length="255"; property - name ="permissions" - column ="permissions" + name="permissions" + column="permissions" ormtype="string" notnull="false" default="" - length ="500"; + length="500"; property - name ="redirect" - column ="redirect" + name="redirect" + column="redirect" ormtype="string" notnull="false" default="" - length ="500"; + length="500"; property - name ="overrideEvent" - column ="overrideEvent" + name="overrideEvent" + column="overrideEvent" ormtype="string" notnull="false" default="" - length ="500"; + length="500"; property - name ="useSSL" - column ="useSSL" + name="useSSL" + column="useSSL" ormtype="boolean" notnull="false" default="false"; property - name ="action" - column ="action" - ormtype ="string" - notnull ="false" - default ="redirect" + name="action" + column="action" + ormtype="string" + notnull="false" + default="redirect" dbdefault="'redirect'" - length ="50"; + length="50"; property - name ="module" - column ="module" + name="module" + column="module" ormtype="string" notnull="false" default="" - length ="500"; + length="500"; property - name ="httpMethods" - column ="httpMethods" - ormtype ="string" - notnull ="true" - default ="*" + name="httpMethods" + column="httpMethods" + ormtype="string" + notnull="true" + default="*" dbdefault="'*'" - length ="255"; + length="255"; property - name ="allowedIPs" - column ="allowedIPs" - ormtype ="string" - notnull ="true" - default ="*" + name="allowedIPs" + column="allowedIPs" + ormtype="string" + notnull="true" + default="*" dbdefault="'*'" - length ="255"; + length="255"; property - name ="order" - column ="order" + name="order" + column="order" ormtype="integer" notnull="true" default="0"; property - name ="message" - column ="message" + name="message" + column="message" ormtype="string" notnull="false" default="" - length ="255"; + length="255"; property - name ="messageType" - column ="messageType" - ormtype ="string" - notnull ="false" - default ="info" + name="messageType" + column="messageType" + ormtype="string" + notnull="false" + default="info" dbdefault="'info'" - length ="50"; - - /* ********************************************************************* - ** PK + CONSTRAINTS - ********************************************************************* */ + length="50"; + /********************************************************************** + * ** PK + CONSTRAINTS + **********************************************************************/ this.pk = "ruleID"; this.memento = { - defaultIncludes : [ + defaultIncludes: [ "action", "allowedIps", "httpMethods", @@ -174,52 +172,52 @@ component "useSSL", "whitelist" ], - defaultExcludes : [ "" ] + defaultExcludes: [ ""] }; this.constraints = { - "whitelist" : { required : false, size : "1..255" }, - "securelist" : { required : true, size : "1..255" }, - "match" : { - required : false, - size : "1..50", - regex : "^(event|url)$" + "whitelist" : { required: false, size: "1..255" }, + "securelist": { required: true, size: "1..255" }, + "match" : { + required: false, + size : "1..50", + regex : "^(event|url)$" }, - "roles" : { required : false, size : "1..255" }, - "permissions" : { required : false, size : "1..500" }, - "redirect" : { required : false, size : "1..500" }, - "overrideEvent" : { required : false, size : "1..500" }, - "useSSL" : { required : false, type : "boolean" }, - "action" : { - required : false, - size : "1..50", - regex : "^(redirect|override)$" + "roles" : { required: false, size: "1..255" }, + "permissions" : { required: false, size: "1..500" }, + "redirect" : { required: false, size: "1..500" }, + "overrideEvent": { required: false, size: "1..500" }, + "useSSL" : { required: false, type: "boolean" }, + "action" : { + required: false, + size : "1..50", + regex : "^(redirect|override)$" }, - "module" : { required : false, size : "1..255" }, - "order" : { required : false, type : "numeric" }, - "message" : { required : false, size : "1..255" }, - "messageType" : { required : false, size : "1..50" } + "module" : { required: false, size: "1..255" }, + "order" : { required: false, type: "numeric" }, + "message" : { required: false, size: "1..255" }, + "messageType": { required: false, size: "1..50" } }; - /* ********************************************************************* - ** PUBLIC FUNCTIONS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC FUNCTIONS + **********************************************************************/ // Constructor - function init(){ - variables.match = "event"; - variables.action = "redirect"; - variables.useSSL = false; - variables.order = 0; - variables.messageType = "info"; + function init() { + variables.match = "event"; + variables.action = "redirect"; + variables.useSSL = false; + variables.order = 0; + variables.messageType = "info"; variables.overrideEvent = ""; - variables.module = ""; - variables.httpMethods = "*"; - variables.allowedIPs = "*"; + variables.module = ""; + variables.httpMethods = "*"; + variables.allowedIPs = "*"; super.init(); return this; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/security/SecurityRuleService.cfc b/modules/contentbox/models/security/SecurityRuleService.cfc index d19a72d73c..ebeb305d3b 100755 --- a/modules/contentbox/models/security/SecurityRuleService.cfc +++ b/modules/contentbox/models/security/SecurityRuleService.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -6,15 +6,15 @@ * Security rules manager */ component extends="cborm.models.VirtualEntityService" singleton { - // DI property name="populator" inject="wirebox:populator"; + property name="dateUtil" inject="DateUtil@contentbox"; /** * Constructor */ - SecurityRuleService function init(){ + SecurityRuleService function init() { // init it super.init( entityName = "cbSecurityRule" ); @@ -24,8 +24,11 @@ component extends="cborm.models.VirtualEntityService" singleton { /** * Get the maximum used order */ - numeric function getMaxOrder(){ - var q = executeQuery( query = "select max( sr.order ) from cbSecurityRule as sr", asQuery = false ); + numeric function getMaxOrder() { + var q = executeQuery( + query = "select max( sr.order ) from cbSecurityRule as sr", + asQuery = false + ); if ( arrayIsDefined( q, 1 ) ) { return q[ 1 ]; } @@ -35,7 +38,7 @@ component extends="cborm.models.VirtualEntityService" singleton { /** * Get the next maximum used order */ - numeric function getNextMaxOrder(){ + numeric function getNextMaxOrder() { return getMaxOrder() + 1; } @@ -47,7 +50,7 @@ component extends="cborm.models.VirtualEntityService" singleton { boolean forceInsert = false, boolean flush = false, boolean transactional = getUseTransactions() - ){ + ) { // determine new or not if ( !arguments.entity.isLoaded() ) { // new, so add next max order if not default @@ -62,14 +65,14 @@ component extends="cborm.models.VirtualEntityService" singleton { /** * Get all rules in firing order */ - query function getSecurityRules(){ + query function getSecurityRules() { return list( sortOrder = "order asc", asQuery = true ); } /** * Reset rules to factory shipping standards, this will remove all rules also */ - any function resetRules(){ + any function resetRules() { transaction { // Get rules path var rulesPath = getDirectoryFromPath( getMetadata( this ).path ) & "data/securityRules.json"; @@ -83,7 +86,7 @@ component extends="cborm.models.VirtualEntityService" singleton { if ( structKeyExists( thisRule, "ruleID" ) ) { structDelete( thisRule, "ruleID" ); } - var oRule = new ( properties = thisRule ); + var oRule = new( properties = thisRule ); save( entity = oRule, transactional = false ); } } @@ -94,10 +97,12 @@ component extends="cborm.models.VirtualEntityService" singleton { /** * Get all data prepared for export */ - array function getAllForExport(){ - return getAll().map( function( thisItem ){ - return thisItem.getMemento( profile: "export" ); - } ); + array function getAllForExport() { + return getAll().map( + function( thisItem ) { + return thisItem.getMemento( profile = "export" ); + } + ); } /** @@ -110,14 +115,17 @@ component extends="cborm.models.VirtualEntityService" singleton { * * @throws InvalidImportFormat */ - string function importFromFile( required importFile, boolean override = false ){ - var data = fileRead( arguments.importFile ); + string function importFromFile( required importFile, boolean override = false ) { + var data = fileRead( arguments.importFile ); var importLog = createObject( "java", "java.lang.StringBuilder" ).init( - "Starting import with override = #arguments.override#...
    " - ); + "Starting import with override = #arguments.override#...
    " + ); if ( !isJSON( data ) ) { - throw( message = "Cannot import file as the contents is not JSON", type = "InvalidImportFormat" ); + throw( + message = "Cannot import file as the contents is not JSON", + type = "InvalidImportFormat" + ); } // deserialize packet: Should be array of { settingID, name, value } @@ -141,12 +149,12 @@ component extends="cborm.models.VirtualEntityService" singleton { required importData, boolean override = false, importLog - ){ + ) { var allRules = []; // if struct, inflate into an array if ( isStruct( arguments.importData ) ) { - arguments.importData = [ arguments.importData ]; + arguments.importData = [ arguments.importData]; } transaction { @@ -154,34 +162,38 @@ component extends="cborm.models.VirtualEntityService" singleton { for ( var thisRule in arguments.importData ) { // Get new or persisted with enough info to match var oRule = this.findWhere( - criteria = { - match : thisRule.match, - whitelist : thisRule.whitelist, - securelist : thisRule.securelist, - redirect : thisRule.redirect, - roles : thisRule.roles, - permissions : thisRule.permissions - } - ); - oRule = ( isNull( oRule ) ? new () : oRule ); + criteria = { + match : thisRule.match, + whitelist : thisRule.whitelist, + securelist : thisRule.securelist, + redirect : thisRule.redirect, + roles : thisRule.roles, + permissions: thisRule.permissions + } + ); + oRule = ( isNull( oRule ) ? new() : oRule ); // populate content from data getBeanPopulator().populateFromStruct( - target = oRule, - memento = thisRule, - exclude = "ruleID", - composeRelationships = false - ); + target = oRule, + memento = thisRule, + exclude = "ruleID", + composeRelationships = false + ); // if new or persisted with override then save. if ( !oRule.isLoaded() ) { arguments.importLog.append( "New security rule imported: #thisRule.toString()#
    " ); arrayAppend( allRules, oRule ); - } else if ( oRule.isLoaded() and arguments.override ) { - arguments.importLog.append( "Persisted security rule overriden: #thisRule.toString()#
    " ); + } else if ( oRule.isLoaded() && arguments.override ) { + arguments.importLog.append( + "Persisted security rule overriden: #thisRule.toString()#
    " + ); arrayAppend( allRules, oRule ); } else { - arguments.importLog.append( "Skipping persisted security rule: #thisRule.toString()#
    " ); + arguments.importLog.append( + "Skipping persisted security rule: #thisRule.toString()#
    " + ); } } // end import loop @@ -192,8 +204,8 @@ component extends="cborm.models.VirtualEntityService" singleton { arguments.importLog.append( "Saved all imported and overriden security rules!" ); } else { arguments.importLog.append( - "No security rules imported as none where found or able to be overriden from the import file." - ); + "No security rules imported as none where found or able to be overriden from the import file." + ); } } // end transaction @@ -201,4 +213,4 @@ component extends="cborm.models.VirtualEntityService" singleton { return arguments.importLog.toString(); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/security/SecurityService.cfc b/modules/contentbox/models/security/SecurityService.cfc index dbf3f625e0..f2870751d5 100755 --- a/modules/contentbox/models/security/SecurityService.cfc +++ b/modules/contentbox/models/security/SecurityService.cfc @@ -6,32 +6,42 @@ * Our contentbox security service must match our interface: ISecurityService */ component singleton { - // Dependencies property name="authorService" inject="authorService@contentbox"; + property name="settingService" inject="settingService@contentbox"; + property name="siteService" inject="siteService@contentbox"; + property name="cacheStorage" inject="cacheStorage@cbStorages"; + property name="cookieStorage" inject="cookieStorage@cbStorages"; + property name="requestStorage" inject="RequestStorage@cbstorages"; + property name="mailService" inject="mailService@cbmailservices"; + property name="renderer" inject="coldbox:renderer"; + property name="CBHelper" inject="CBHelper@contentbox"; + property name="log" inject="logbox:logger:{this}"; + property name="cache" inject="cachebox:template"; + property name="bCrypt" inject="BCrypt@BCrypt"; + property name="cbCSRF" inject="@cbcsrf"; // Properties property name="encryptionKey"; - // Static key to identify an author in a request: more for api interaction than web. variables.AUTHOR_KEY = "contentbox_author"; /** * Constructor */ - SecurityService function init(){ + SecurityService function init() { variables.encryptionKey = ""; return this; } @@ -41,7 +51,7 @@ component singleton { * * @author The author object */ - Author function updateAuthorLoginTimestamp( required author ){ + Author function updateAuthorLoginTimestamp( required author ) { arguments.author.setLastLogin( now() ); variables.authorService.save( arguments.author ); return arguments.author; @@ -50,7 +60,7 @@ component singleton { /** * Alias to getAuthorSession() created to satisfy JWT Services */ - function getUser(){ + function getUser() { return this.getAuthorSession(); } @@ -64,7 +74,7 @@ component singleton { * * @return Logged in or new author object */ - Author function getAuthorSession(){ + Author function getAuthorSession() { // Check if valid author id in session or request respectively var oAuthor = variables.requestStorage.get( variables.AUTHOR_KEY, variables.authorService.new() ); if ( oAuthor.isLoggedIn() ) { @@ -81,7 +91,7 @@ component singleton { // If we found an authorID, load it up and check it if ( len( authorID ) ) { // try to get it with that ID - var author = variables.authorService.findWhere( { authorID : authorID, isActive : true, isDeleted : false } ); + var author = variables.authorService.findWhere( { authorID: authorID, isActive: true, isDeleted: false } ); // If user found? Inflate them back if ( !isNull( author ) ) { return login( author ); @@ -95,7 +105,7 @@ component singleton { /** * Verifies if a user is logged in or not. Required for JWT Services */ - boolean function isLoggedIn(){ + boolean function isLoggedIn() { var oAuthor = this.getAuthorSession(); return oAuthor.isLoaded() && oAuthor.isLoggedIn(); } @@ -105,7 +115,7 @@ component singleton { * * @author The author to log in */ - Author function login( required author ){ + Author function login( required author ) { // Mark as logged in arguments.author.setLoggedIn( true ); // Store for the duration of the request, API mode @@ -120,7 +130,7 @@ component singleton { * * @return SecurityService */ - SecurityService function logout(){ + SecurityService function logout() { variables.requestStorage.delete( variables.AUTHOR_KEY ); variables.cacheStorage.clearAll(); variables.cookieStorage.delete( "contentbox_keep_logged_in" ); @@ -149,32 +159,38 @@ component singleton { required username, required password, boolean logThemIn = false - ){ + ) { // Find them try { var oAuthor = variables.authorService.retrieveUserByUsername( arguments.username ); - } catch ( EntityNotFound e ) { + } catch (EntityNotFound e) { variables.log.warn( - "Invalid username authentication from #getRealIP()# for username: #arguments.username#", - getHTTPRequestData( false ) + "Invalid username authentication from #getRealIP()# for username: #arguments.username#", + getHTTPRequestData( false ) + ); + throw( + type = "InvalidCredentials", + message = "Incorrect Credentials Entered" ); - throw( type = "InvalidCredentials", message = "Incorrect Credentials Entered" ); } // Validate password using bcrypt try { var isSamePassword = variables.bcrypt.checkPassword( arguments.password, oAuthor.getPassword() ); - } catch ( any e ) { + } catch (any e) { var isSamePassword = false; } // Verify Password if ( !isSamePassword ) { variables.log.warn( - "Invalid password authentication from #getRealIP()# for username: #arguments.username#", - getHTTPRequestData( false ) + "Invalid password authentication from #getRealIP()# for username: #arguments.username#", + getHTTPRequestData( false ) + ); + throw( + type = "InvalidCredentials", + message = "Incorrect Credentials Entered" ); - throw( type = "InvalidCredentials", message = "Incorrect Credentials Entered" ); } // Set last login date @@ -193,7 +209,7 @@ component singleton { * * @string The string to bcrypt */ - string function encryptString( required string ){ + string function encryptString( required string ) { return variables.bCrypt.hashPassword( arguments.string ); } @@ -202,16 +218,18 @@ component singleton { * * @author The author to create the reset token for. */ - string function generateResetToken( required Author author ){ + string function generateResetToken( required Author author ) { var tokenTimeout = variables.settingService.getSetting( "cb_security_password_reset_expiration" ); // Store Security Token For X minutes - var token = hash( arguments.author.getEmail() & arguments.author.getAuthorID() & now() ); - cache.set( - "reset-token-#token#", - arguments.author.getAuthorID(), - tokenTimeout, - tokenTimeout + var token = hash( + arguments.author.getEmail() & arguments.author.getAuthorID() & now() ); + cache.set( + "reset-token-#token#", + arguments.author.getAuthorID(), + tokenTimeout, + tokenTimeout + ); return token; } @@ -229,45 +247,46 @@ component singleton { required Author author, boolean adminIssued = false, Author issuer - ){ + ) { // Generate security token var token = generateResetToken( arguments.author ); // get settings - var settings = variables.settingService.getAllSettings(); + var settings = variables.settingService.getAllSettings(); var defaultSite = variables.siteService.getDefaultSite(); // get mail payload var bodyTokens = { - name : arguments.author.getFullName(), - ip : getRealIP(), - linkTimeout : settings.cb_security_password_reset_expiration, - siteName : defaultSite.getName(), - linkToken : CBHelper.linkAdmin( event = "security.verifyReset", ssl = settings.cb_admin_ssl ) & "?token=#token#", - issuedBy : "", - issuedEmail : "" + name : arguments.author.getFullName(), + ip : getRealIP(), + linkTimeout: settings.cb_security_password_reset_expiration, + siteName : defaultSite.getName(), + linkToken : CBHelper.linkAdmin( event = "security.verifyReset", + ssl = settings.cb_admin_ssl ) & "?token=#token#", + issuedBy : "", + issuedEmail: "" }; // Check if an issuer was passed if ( !isNull( arguments.issuer ) ) { - bodyTokens.issuedBy = arguments.issuer.getFullName(); + bodyTokens.issuedBy = arguments.issuer.getFullName(); bodyTokens.issuedEmail = arguments.issuer.getEmail(); } // Build email out var mail = variables.mailservice.newMail( - to = arguments.author.getEmail(), - from = settings.cb_site_outgoingEmail, - subject = "#defaultSite.getName()# Password Reset Verification", - bodyTokens = bodyTokens, - type = "html", - server = settings.cb_site_mail_server, - username = settings.cb_site_mail_username, - password = settings.cb_site_mail_password, - port = settings.cb_site_mail_smtp, - useTLS = settings.cb_site_mail_tls, - useSSL = settings.cb_site_mail_ssl - ); + to = arguments.author.getEmail(), + from = settings.cb_site_outgoingEmail, + subject = "#defaultSite.getName()# Password Reset Verification", + bodyTokens = bodyTokens, + type = "html", + server = settings.cb_site_mail_server, + username = settings.cb_site_mail_username, + password = settings.cb_site_mail_password, + port = settings.cb_site_mail_smtp, + useTLS = settings.cb_site_mail_tls, + useSSL = settings.cb_site_mail_ssl + ); // Decide template depending if issued by user or admin var emailTemplate = "password_verification"; @@ -276,11 +295,11 @@ component singleton { } mail.setBody( - renderer.layout( - view = "/contentbox/email_templates/#emailTemplate#", - layout = "/contentbox/email_templates/layouts/email" - ) - ); + renderer.layout( + view = "/contentbox/email_templates/#emailTemplate#", + layout = "/contentbox/email_templates/layouts/email" + ) + ); // send it out return mailService.send( mail ).getResults(); @@ -294,8 +313,8 @@ component singleton { * * @return {error, author} */ - struct function validateResetToken( required token ){ - var results = { "error" : false, "author" : "" }; + struct function validateResetToken( required token ) { + var results = { "error": false, "author": "" }; var cacheKey = "reset-token-#arguments.token#"; var authorID = cache.get( cacheKey ); @@ -303,14 +322,14 @@ component singleton { if ( isNull( authorID ) ) { results.error = true; return results; - }; + } // Verify the author of the token results.author = variables.authorService.get( authorID ); if ( isNull( results.author ) ) { results.error = true; return results; - }; + } return results; } @@ -328,30 +347,30 @@ component singleton { required token, required Author author, required password - ){ - var results = { "error" : false, "messages" : "" }; + ) { + var results = { "error": false, "messages": "" }; var cacheKey = "reset-token-#arguments.token#"; var authorID = cache.get( cacheKey ); // If token not found, don't reset and return back if ( isNull( authorID ) ) { - results.error = true; + results.error = true; results.messages = "Token does not exist or has expired"; return results; - }; + } // Verify the author of the token - if ( arguments.author.getAuthorID() neq authorID ) { - results.error = true; + if ( arguments.author.getAuthorID() NEQ authorID ) { + results.error = true; results.messages = "Author reset token mismatch"; return results; - }; + } // Remove token now that we have the data and it has been validated cache.clear( cacheKey ); // get settings - var settings = settingService.getAllSettings(); + var settings = settingService.getAllSettings(); var defaultSite = variables.siteService.getDefaultSite(); // set it in the user and save reset password @@ -361,32 +380,32 @@ component singleton { // get mail payload var bodyTokens = { - name : arguments.author.getFullName(), - ip : getRealIP(), - linkLogin : CBHelper.linkAdminLogin( ssl = settings.cb_admin_ssl ), - siteName : defaultSite.getName(), - adminEmail : settings.cb_site_email + name : arguments.author.getFullName(), + ip : getRealIP(), + linkLogin : CBHelper.linkAdminLogin( ssl = settings.cb_admin_ssl ), + siteName : defaultSite.getName(), + adminEmail: settings.cb_site_email }; var mail = mailservice.newMail( - to = arguments.author.getEmail(), - from = settings.cb_site_outgoingEmail, - subject = "#defaultSite.getName()# Password Reset Completed", - bodyTokens = bodyTokens, - type = "html", - server = settings.cb_site_mail_server, - username = settings.cb_site_mail_username, - password = settings.cb_site_mail_password, - port = settings.cb_site_mail_smtp, - useTLS = settings.cb_site_mail_tls, - useSSL = settings.cb_site_mail_ssl - ); + to = arguments.author.getEmail(), + from = settings.cb_site_outgoingEmail, + subject = "#defaultSite.getName()# Password Reset Completed", + bodyTokens = bodyTokens, + type = "html", + server = settings.cb_site_mail_server, + username = settings.cb_site_mail_username, + password = settings.cb_site_mail_password, + port = settings.cb_site_mail_smtp, + useTLS = settings.cb_site_mail_tls, + useSSL = settings.cb_site_mail_ssl + ); // ,body=renderer.$get().externalView(view="/contentbox/email_templates/password_reminder" ) mail.setBody( - renderer.layout( - view = "/contentbox/email_templates/password_reset", - layout = "/contentbox/email_templates/layouts/email" - ) - ); + renderer.layout( + view = "/contentbox/email_templates/password_reset", + layout = "/contentbox/email_templates/layouts/email" + ) + ); // send it out mailService.send( mail ); @@ -399,14 +418,14 @@ component singleton { * @content The content object * @password The password to check */ - boolean function authorizeContent( required content, required password ){ + boolean function authorizeContent( required content, required password ) { // Validate Password - if ( compare( arguments.content.getPasswordProtection(), arguments.password ) eq 0 ) { + if ( compare( arguments.content.getPasswordProtection(), arguments.password ) EQ 0 ) { // Set simple validation cacheStorage.set( - "protection-#hash( arguments.content.getSlug() )#", - getContentProtectedHash( arguments.content ) - ); + "protection-#hash( arguments.content.getSlug() )#", + getContentProtectedHash( arguments.content ) + ); return true; } @@ -418,52 +437,54 @@ component singleton { * * @content The content object to check */ - boolean function isContentViewable( required content ){ + boolean function isContentViewable( required content ) { var protectedHash = cacheStorage.get( "protection-#hash( arguments.content.getSlug() )#", "" ); // check hash against validated content - if ( compare( protectedHash, getContentProtectedHash( arguments.content ) ) EQ 0 ) { + if ( + compare( + protectedHash, + getContentProtectedHash( arguments.content ) + ) EQ + 0 + ) { return true; } return false; } - /** - * Get password content protected salt - * - * @content The content object - */ - private string function getContentProtectedHash( required content ){ - return hash( arguments.content.getSlug() & arguments.content.getPasswordProtection(), "SHA-256" ); - } - /** * Get remember me cookie */ - any function getRememberMe(){ + any function getRememberMe() { var cookieValue = cookieStorage.get( "contentbox_remember_me", "" ); try { return decryptIt( cookieValue ); - } catch ( Any e ) { + } catch (Any e) { // Errors on decryption - log.error( "Error decrypting remember me key: #e.message# #e.detail#", cookieValue ); + log.error( + "Error decrypting remember me key: #e.message# #e.detail#", + cookieValue + ); cookieStorage.delete( "contentbox_remember_me" ); return ""; } } - /** * Get keep me logged in cookie */ - any function getKeepMeLoggedIn(){ + any function getKeepMeLoggedIn() { var cookieValue = cookieStorage.get( "contentbox_keep_logged_in", "" ); try { return decryptIt( cookieValue ); - } catch ( Any e ) { + } catch (Any e) { // Errors on decryption - log.error( "Error decrypting Keep Me Logged in key: #e.message# #e.detail#", cookieValue ); + log.error( + "Error decrypting Keep Me Logged in key: #e.message# #e.detail#", + cookieValue + ); cookieStorage.delete( "contentbox_keep_logged_in" ); return ""; } @@ -475,7 +496,7 @@ component singleton { * @username The username to store * @days The days to store */ - SecurityService function setRememberMe( required username, required numeric days = 0 ){ + SecurityService function setRememberMe( required username, required numeric days = 0 ) { // If the user now only wants to be remembered for this session, remove any existing cookies. if ( !arguments.days ) { variables.cookieStorage.delete( "contentbox_remember_me" ); @@ -485,24 +506,26 @@ component singleton { // Save the username to pre-populate the login field after their login expires for up to a year. variables.cookieStorage.set( - name = "contentbox_remember_me", - value = encryptIt( arguments.username ), - expires = 365 - ); + name = "contentbox_remember_me", + value = encryptIt( arguments.username ), + expires = 365 + ); // Look up the user ID and store for the duration specified - var author = variables.authorService.findWhere( { - username : arguments.username, - isActive : true, - isDeleted : false - } ); + var author = variables.authorService.findWhere( + { + username : arguments.username, + isActive : true, + isDeleted: false + } + ); if ( !isNull( author ) ) { // The user will be auto-logged in as long as this cookie exists variables.cookieStorage.set( - name = "contentbox_keep_logged_in", - value = encryptIt( author.getAuthorID() ), - expires = arguments.days - ); + name = "contentbox_keep_logged_in", + value = encryptIt( author.getAuthorID() ), + expires = arguments.days + ); } return this; @@ -513,7 +536,7 @@ component singleton { * * @encValue value to encrypt */ - string function encryptIt( required encValue ){ + string function encryptIt( required encValue ) { // if empty just return it if ( !len( arguments.encValue ) ) { return arguments.encValue; @@ -531,7 +554,7 @@ component singleton { * * @decValue value to decrypt */ - string function decryptIt( required decValue ){ + string function decryptIt( required decValue ) { if ( !len( arguments.decValue ) ) { return arguments.decValue; } @@ -547,21 +570,23 @@ component singleton { * Verifies we have a salt in our installation * if not, it will generate a new cb_enc_key */ - string function getEncryptionKey(){ + string function getEncryptionKey() { // Is the encryption key loaded? if ( len( variables.encryptionKey ) ) { return variables.encryptionKey; } // Verify we have one in the installation, else generate one - var oSetting = settingService.findWhere( { name : "cb_enc_key" } ); + var oSetting = settingService.findWhere( { name: "cb_enc_key" } ); // if no key, then create it for this ContentBox installation if ( isNull( oSetting ) ) { - oSetting = settingService.new( { - name : "cb_enc_key", - value : generateSecretKey( "BLOWFISH" ) - } ); + oSetting = settingService.new( + { + name : "cb_enc_key", + value: generateSecretKey( "BLOWFISH" ) + } + ); settingService.save( entity = oSetting ); log.info( "Registered new cookie encryption key" ); } @@ -576,7 +601,7 @@ component singleton { /** * Get Real IP, by looking at clustered, proxy headers and locally. */ - function getRealIP(){ + function getRealIP() { var headers = getHTTPRequestData( false ).headers; // When going through a proxy, the IP can be a delimtied list, thus we take the last one in the list @@ -591,4 +616,16 @@ component singleton { return len( cgi.remote_addr ) ? trim( listFirst( cgi.remote_addr ) ) : "127.0.0.1"; } -} + /** + * Get password content protected salt + * + * @content The content object + */ + private string function getContentProtectedHash( required content ) { + return hash( + arguments.content.getSlug() & arguments.content.getPasswordProtection(), + "SHA-256" + ); + } + +} \ No newline at end of file diff --git a/modules/contentbox/models/security/SecurityValidator.cfc b/modules/contentbox/models/security/SecurityValidator.cfc index 98a8cd0070..5a1782cb96 100644 --- a/modules/contentbox/models/security/SecurityValidator.cfc +++ b/modules/contentbox/models/security/SecurityValidator.cfc @@ -6,12 +6,7 @@ * This is our security validator that works with CBSecurity in order to validate * rules and annotations. */ -component - singleton - threadsafe - extends="cbsecurity.models.validators.AuthValidator" -{ - +component singleton threadsafe extends="cbsecurity.models.validators.AuthValidator" { // Dependencies property name="securityService" inject="securityService@contentbox"; @@ -27,11 +22,11 @@ component * * @return { allow:boolean, type:string(authentication|authorization), messages:string } */ - struct function ruleValidator( required rule, required controller ){ + struct function ruleValidator( required rule, required controller ) { return validateSecurity( - rule : arguments.rule, - securedValue: arguments.rule.permissions, - controller : arguments.controller + rule = arguments.rule, + securedValue = arguments.rule.permissions, + controller = arguments.controller ); } @@ -46,8 +41,8 @@ component * * @return { allow:boolean, type:string(authentication|authorization), messages:string } */ - struct function annotationValidator( required securedValue, required controller ){ - return validateSecurity( securedValue: arguments.securedValue, controller: arguments.controller ); + struct function annotationValidator( required securedValue, required controller ) { + return validateSecurity( securedValue = arguments.securedValue, controller = arguments.controller ); } /** @@ -59,7 +54,7 @@ component * * @return Validation struct of: { allow:boolean, type:(authentication|authorization), messages } */ - struct function validateSecurity( struct rule, securedValue = "", any controller ){ + struct function validateSecurity( struct rule, securedValue = "", any controller ) { var results = super.validateSecurity( arguments.securedValue ); // If we are allowing, then continue to test the ContentBox roles @@ -70,9 +65,12 @@ component // Check if the rule requires roles if ( !isNull( arguments.rule ) && len( arguments.rule.roles ) ) { results.allow = false; - results.type = "authorization"; - for ( var thisRole in arguments.rule.roles.listToArray() ) { - if ( oAuthor.getRoleName() eq thisRole ) { + results.type = "authorization"; + for ( var thisRole in arguments + .rule + .roles + .listToArray() ) { + if ( oAuthor.getRoleName() EQ thisRole ) { results.allow = true; break; } @@ -82,21 +80,22 @@ component // If the rule has a message, then set a messagebox if ( - !results.allow && - !isNull( arguments.rule ) && - !isNull( arguments.rule.message ) && - len( arguments.rule.message ) + !results.allow && !isNull( arguments.rule ) && !isNull( arguments.rule.message ) && + len( arguments.rule.message ) ) { - arguments.controller + arguments + .controller .getWireBox() .getInstance( "messagebox@cbmessagebox" ) .setMessage( - type : ( structKeyExists( rule, "messageType" ) && len( rule.messageType ) ? rule.messageType : "info" ), - message: rule.message + type = ( + structKeyExists( rule, "messageType" ) && len( rule.messageType ) ? rule.messageType : "info" + ), + message = rule.message ); } return results; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/security/twofactor/BaseTwoFactorProvider.cfc b/modules/contentbox/models/security/twofactor/BaseTwoFactorProvider.cfc index 62d31f4ba0..e7bb3f3d94 100644 --- a/modules/contentbox/models/security/twofactor/BaseTwoFactorProvider.cfc +++ b/modules/contentbox/models/security/twofactor/BaseTwoFactorProvider.cfc @@ -13,26 +13,30 @@ * - CBHelper */ component { - // DI property name="log" inject="logbox:logger:{this}"; + property name="settingService" inject="settingService@contentbox"; + property name="securityService" inject="securityService@contentbox"; + property name="siteService" inject="siteService@contentbox"; + property name="renderer" inject="coldbox:renderer"; + property name="CBHelper" inject="id:CBHelper@contentbox"; /** * Constructor */ - function init(){ + function init() { return this; } /** * Get all system settings */ - struct function getAllSettings(){ + struct function getAllSettings() { return variables.settingService.getAllSettings(); } @@ -41,7 +45,7 @@ component { * * @return Site */ - function getDefaultSite(){ + function getDefaultSite() { return variables.siteService.getDefaultSite(); } @@ -50,8 +54,8 @@ component { * * @return Site */ - function discoverSite(){ + function discoverSite() { return variables.siteService.discoverSite(); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/security/twofactor/ITwoFactorProvider.cfc b/modules/contentbox/models/security/twofactor/ITwoFactorProvider.cfc index 84457a057c..6225dbaa14 100644 --- a/modules/contentbox/models/security/twofactor/ITwoFactorProvider.cfc +++ b/modules/contentbox/models/security/twofactor/ITwoFactorProvider.cfc @@ -67,5 +67,4 @@ interface { * @author The author to verify challenge */ function finalize( required string code, required author ); - -} +} \ No newline at end of file diff --git a/modules/contentbox/models/security/twofactor/TwoFactorService.cfc b/modules/contentbox/models/security/twofactor/TwoFactorService.cfc index 9e68425d9c..0ce150083d 100644 --- a/modules/contentbox/models/security/twofactor/TwoFactorService.cfc +++ b/modules/contentbox/models/security/twofactor/TwoFactorService.cfc @@ -6,19 +6,21 @@ * Manages Two Factor Authenticators */ component accessors="true" threadSafe singleton { - // DI property name="settingService" inject="settingService@contentbox"; + property name="securityService" inject="securityService@contentbox"; + property name="authorService" inject="authorService@contentbox"; + property name="cookieStorage" inject="cookieStorage@cbStorages"; + property name="log" inject="logbox:logger:{this}"; /** * Providers registry */ property name="providers" type="struct"; - // Static Properties variables.TRUSTED_DEVICE_COOKIE = "contentbox_2factor_device"; @@ -28,7 +30,7 @@ component accessors="true" threadSafe singleton { * * @wirebox.inject wirebox */ - TwoFactorService function init( required wirebox ){ + TwoFactorService function init( required wirebox ) { // init providers variables.providers = {}; @@ -41,7 +43,7 @@ component accessors="true" threadSafe singleton { /** * Are we forcing global two factor authentication */ - boolean function isForceTwoFactorAuth(){ + boolean function isForceTwoFactorAuth() { // Doing !! to force a boolean return !!settingService.getSetting( "cb_security_2factorAuth_force" ); } @@ -49,21 +51,21 @@ component accessors="true" threadSafe singleton { /** * Get the default system provider name */ - string function getDefaultProvider(){ + string function getDefaultProvider() { return settingService.getSetting( "cb_security_2factorAuth_provider" ); } /** * Get the default system provider object */ - contentbox.models.security.twofactor.ITwoFactorProvider function getDefaultProviderObject(){ + contentbox.models.security.twofactor.ITwoFactorProvider function getDefaultProviderObject() { return getProvider( getDefaultProvider() ); } /** * Get the default system trusted device timespan */ - numeric function getTrustedDeviceTimespan(){ + numeric function getTrustedDeviceTimespan() { return settingService.getSetting( "cb_security_2factorAuth_trusted_days" ); } @@ -74,7 +76,7 @@ component accessors="true" threadSafe singleton { */ TwoFactorService function registerProvider( required contentbox.models.security.twofactor.ITwoFactorProvider provider - ){ + ) { variables.providers[ arguments.provider.getName() ] = arguments.provider; return this; } @@ -84,7 +86,7 @@ component accessors="true" threadSafe singleton { * * @name The name of the provider to unregister */ - TwoFactorService function unRegisterProvider( required name ){ + TwoFactorService function unRegisterProvider( required name ) { structDelete( variables.providers, arguments.name ); return this; } @@ -92,22 +94,24 @@ component accessors="true" threadSafe singleton { /** * Get an array of registered provider names in alphabetical order */ - array function getRegisteredProviders(){ - return listToArray( listSort( structKeyList( variables.providers ), "textnocase" ) ); + array function getRegisteredProviders() { + return listToArray( + listSort( structKeyList( variables.providers ), "textnocase" ) + ); } /** * Get an array of registered provider names in alphabetical order with their display names */ - array function getRegisteredProvidersMap(){ + array function getRegisteredProvidersMap() { var aProviders = getRegisteredProviders(); - var result = []; + var result = []; for ( var thisProvider in aProviders ) { arrayAppend( result, { - name : thisProvider, - displayName : variables.providers[ thisProvider ].getDisplayName() + name : thisProvider, + displayName: variables.providers[ thisProvider ].getDisplayName() } ); } @@ -119,7 +123,7 @@ component accessors="true" threadSafe singleton { * * @name The name of the provider */ - contentbox.models.security.twofactor.ITwoFactorProvider function getProvider( required name ){ + contentbox.models.security.twofactor.ITwoFactorProvider function getProvider( required name ) { return variables.providers[ arguments.name ]; } @@ -128,7 +132,7 @@ component accessors="true" threadSafe singleton { * * @name The name of the provider */ - boolean function hasProvider( required name ){ + boolean function hasProvider( required name ) { return structKeyExists( variables.providers, arguments.name ); } @@ -137,12 +141,12 @@ component accessors="true" threadSafe singleton { * * @trustedID The trusted ID to track in the tracking cookie */ - TwoFactorService function setTrustedDevice( required trustedID ){ + TwoFactorService function setTrustedDevice( required trustedID ) { cookieStorage.set( - name = variables.TRUSTED_DEVICE_COOKIE, - value = securityService.encryptIt( arguments.trustedID ), - expires = getTrustedDeviceTimespan() - ); + name = variables.TRUSTED_DEVICE_COOKIE, + value = securityService.encryptIt( arguments.trustedID ), + expires = getTrustedDeviceTimespan() + ); return this; } @@ -151,21 +155,24 @@ component accessors="true" threadSafe singleton { * * @trustedID The trusted ID to verify */ - boolean function isTrustedDevice( required trustedID ){ + boolean function isTrustedDevice( required trustedID ) { var cookieValue = cookieStorage.get( name = variables.TRUSTED_DEVICE_COOKIE, defaultValue = "" ); try { // decrypt the target id var targetTrustedID = securityService.decryptIt( cookieValue ); // Verify they are the same - if ( targetTrustedID neq arguments.trustedID ) { + if ( targetTrustedID NEQ arguments.trustedID ) { cookieStorage.delete( variables.TRUSTED_DEVICE_COOKIE ); return false; } return true; - } catch ( Any e ) { + } catch (Any e) { // Errors on decryption - log.error( "Error decrypting trusted id cookie: #e.message# #e.detail#", cookieValue ); + log.error( + "Error decrypting trusted id cookie: #e.message# #e.detail#", + cookieValue + ); cookieStorage.delete( variables.TRUSTED_DEVICE_COOKIE ); return false; } @@ -176,18 +183,16 @@ component accessors="true" threadSafe singleton { * * @author The author to challenge or not */ - boolean function canChallenge( required author ){ + boolean function canChallenge( required author ) { var oProvider = getProvider( getDefaultProvider() ); - var results = false; + var results = false; if ( - // Verify if global force is enabled - isForceTwoFactorAuth() - OR - // Verify if user has two factor auth enabled - arguments.author.getIs2FactorAuth() + isForceTwoFactorAuth() || + arguments.author// Verify if user has two factor auth enabled + .getIs2FactorAuth() ) { // Verify if using trusted device options and if device is trusted - if ( oProvider.allowTrustedDevice() AND isTrustedDevice( arguments.author.getAuthorID() ) ) { + if ( oProvider.allowTrustedDevice() && isTrustedDevice( arguments.author.getAuthorID() ) ) { results = false; } else { results = true; @@ -206,7 +211,7 @@ component accessors="true" threadSafe singleton { * * @return struct:{ error:boolean, messages:string } */ - struct function sendChallenge( required author ){ + struct function sendChallenge( required author ) { return getProvider( getDefaultProvider() ).sendChallenge( arguments.author ); } @@ -219,8 +224,8 @@ component accessors="true" threadSafe singleton { * * @return struct:{ error:boolean, messages:string } */ - struct function verifyChallenge( required string code, required author ){ + struct function verifyChallenge( required string code, required author ) { return getProvider( getDefaultProvider() ).verifyChallenge( arguments.code, arguments.author ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/subscriptions/BaseSubscription.cfc b/modules/contentbox/models/subscriptions/BaseSubscription.cfc index 0b58cfa28e..0384c7854f 100644 --- a/modules/contentbox/models/subscriptions/BaseSubscription.cfc +++ b/modules/contentbox/models/subscriptions/BaseSubscription.cfc @@ -13,105 +13,95 @@ component cachename ="cbSubscription" cacheuse ="read-write" { - - /* ********************************************************************* - ** PROPERTIES again due to ACF Bug - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES again due to ACF Bug + **********************************************************************/ property - name ="createdDate" - column ="createdDate" - type ="date" + name="createdDate" + column="createdDate" + type="date" ormtype="timestamp" notnull="true" - update ="false"; + update="false"; property - name ="modifiedDate" - column ="modifiedDate" - type ="date" + name="modifiedDate" + column="modifiedDate" + type="date" ormtype="timestamp" notnull="true"; property - name ="isDeleted" - column ="isDeleted" + name="isDeleted" + column="isDeleted" ormtype="boolean" notnull="true" default="false"; - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="subscriptionID" - column ="subscriptionID" + name="subscriptionID" + column="subscriptionID" fieldtype="id" generator="uuid" - length ="36" - ormtype ="string" - update ="false"; + length="36" + ormtype="string" + update="false"; /** * This token identifies subscribers (emails) to appropriate subscriptions */ property - name ="subscriptionToken" - column ="subscriptionToken" + name="subscriptionToken" + column="subscriptionToken" ormtype="string" - length ="255" + length="255" notnull="true"; /** * The type of subscriptions. Available subscriptions are : comment */ - property - name ="type" - column ="type" - ormtype="string" - notnull="true"; + property name="type" column="type" ormtype="string" notnull="true"; - /* ********************************************************************* - ** RELATIONSHIPS - ********************************************************************* */ + /********************************************************************** + * ** RELATIONSHIPS + **********************************************************************/ // M20 -> Content loaded as a proxy property - name ="subscriber" - notnull ="true" - cfc ="contentbox.models.subscriptions.Subscriber" + name="subscriber" + notnull="true" + cfc="contentbox.models.subscriptions.Subscriber" fieldtype="many-to-one" - fkcolumn ="FK_subscriberID" - lazy ="true" - inverse ="true" - orderBy ="subscriberEmail"; - - /* ********************************************************************* - ** PK + CONSTRAINTS - ********************************************************************* */ + fkcolumn="FK_subscriberID" + lazy="true" + inverse="true" + orderBy="subscriberEmail"; + /********************************************************************** + * ** PK + CONSTRAINTS + **********************************************************************/ this.pk = "subscriptionID"; this.memento = { - defaultIncludes : [ - "subscriptionToken", - "type", - "subscriberSnapshot:subscriber" - ], - defaultExcludes : [] + defaultIncludes: [ "subscriptionToken", "type", "subscriberSnapshot:subscriber"], + defaultExcludes: [] }; this.constraints = { - "subscriptionToken" : { required : true, size : "1..255" }, - "type" : { required : true, size : "1..255", regex : "^(comment)$" } + "subscriptionToken": { required: true, size: "1..255" }, + "type" : { required: true, size: "1..255", regex: "^(comment)$" } }; - /* ********************************************************************* - ** METHODS - ********************************************************************* */ + /********************************************************************** + * ** METHODS + **********************************************************************/ - function init(){ + function init() { super.init(); return this; } @@ -119,11 +109,11 @@ component /** * Build a snapshot of the subscriber */ - struct function getSubscriberSnapshot(){ + struct function getSubscriberSnapshot() { if ( hasSubscriber() ) { return getSubscriber().getInfoSnapshot(); } return {}; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/subscriptions/CommentSubscription.cfc b/modules/contentbox/models/subscriptions/CommentSubscription.cfc index 0a49b185de..360c6eab22 100644 --- a/modules/contentbox/models/subscriptions/CommentSubscription.cfc +++ b/modules/contentbox/models/subscriptions/CommentSubscription.cfc @@ -14,44 +14,46 @@ component cachename ="cbCommentSubscription" cacheuse ="read-write" { - - /* ********************************************************************* - ** DI - ********************************************************************* */ + /********************************************************************** + * ** DI + **********************************************************************/ property - name ="commentSubscriptionService" - inject ="provider:commentSubscriptionService@contentbox" + name="commentSubscriptionService" + inject="provider:commentSubscriptionService@contentbox" persistent="false"; - /* ********************************************************************* - ** RELATIONSHIPS - ********************************************************************* */ + /********************************************************************** + * ** RELATIONSHIPS + **********************************************************************/ // M20 -> Content loaded as a proxy property - name ="relatedContent" - notnull ="true" - cfc ="contentbox.models.content.BaseContent" + name="relatedContent" + notnull="true" + cfc="contentbox.models.content.BaseContent" fieldtype="many-to-one" - fkcolumn ="FK_contentID" - lazy ="true" - orderBy ="Title ASC"; + fkcolumn="FK_contentID" + lazy="true" + orderBy="Title ASC"; - /* ********************************************************************* - ** METHODS - ********************************************************************* */ + /********************************************************************** + * ** METHODS + **********************************************************************/ - function init(){ + function init() { super.init(); - appendToMemento( [ "relatedContentSnapshot:relatedContent" ], "defaultIncludes" ); + appendToMemento( + [ "relatedContentSnapshot:relatedContent"], + "defaultIncludes" + ); return this; } /** * Build a snapshot of the related content */ - struct function getRelatedContentSnapshot(){ + struct function getRelatedContentSnapshot() { if ( hasRelatedContent() ) { return getRelatedContent().getInfoSnapshot(); } @@ -61,7 +63,7 @@ component /** * Before insertion verify if we have a token, else generate one. */ - public void function preInsert(){ + public void function preInsert() { super.preInsert(); if ( isNull( getSubscriptionToken() ) ) { @@ -70,12 +72,14 @@ component } } - public boolean function isExtantSubscription(){ - var extantSubscription = variables.commentSubscriptionService.findWhere( { - relatedContent : getRelatedContent(), - subscriber : getSubscriber() - } ); + public boolean function isExtantSubscription() { + var extantSubscription = variables.commentSubscriptionService.findWhere( + { + relatedContent: getRelatedContent(), + subscriber : getSubscriber() + } + ); return isNull( extantSubscription ) ? false : true; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/subscriptions/CommentSubscriptionService.cfc b/modules/contentbox/models/subscriptions/CommentSubscriptionService.cfc index 8f8f98ff0f..c7544c64e2 100644 --- a/modules/contentbox/models/subscriptions/CommentSubscriptionService.cfc +++ b/modules/contentbox/models/subscriptions/CommentSubscriptionService.cfc @@ -7,8 +7,11 @@ */ component extends="SubscriptionService" singleton { - function init(){ - super.init( entityName = "cbCommentSubscription", useQueryCaching = true ); + function init() { + super.init( + entityName = "cbCommentSubscription", + useQueryCaching = true + ); return this; } @@ -19,20 +22,23 @@ component extends="SubscriptionService" singleton { * * @return Array of properties: title, relatedContent, subscriberCount or label, value */ - array function getGroupedSubscriptions( required numeric max = 0 ){ + array function getGroupedSubscriptions( required numeric max = 0 ) { if ( !arguments.max ) { - var sortOrder = "title ASC"; + var sortOrder = "title ASC"; var groupProperty = "content.title:title,relatedContent"; - var countAlias = "subscriberCount"; + var countAlias = "subscriberCount"; } else { - var sortOrder = "value DESC"; + var sortOrder = "value DESC"; var groupProperty = "content.title:label"; - var countAlias = "value"; + var countAlias = "value"; } return newCriteria() .joinTo( "relatedContent", "content" ) - .withProjections( groupProperty = groupProperty, count = "subscriber:#countAlias#" ) + .withProjections( + groupProperty = groupProperty, + count = "subscriber:#countAlias#" + ) .asStruct() .list( sortOrder = sortOrder, max = arguments.max ); } @@ -40,8 +46,8 @@ component extends="SubscriptionService" singleton { /** * Get the count of total comment subscriptions */ - public numeric function getGroupedSubscriptionCount(){ + public numeric function getGroupedSubscriptionCount() { return newCriteria().count(); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/subscriptions/Subscriber.cfc b/modules/contentbox/models/subscriptions/Subscriber.cfc index 13cb4623cd..44e580e209 100644 --- a/modules/contentbox/models/subscriptions/Subscriber.cfc +++ b/modules/contentbox/models/subscriptions/Subscriber.cfc @@ -13,76 +13,70 @@ component cachename ="cbSubscriber" cacheuse ="read-write" { - - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="subscriberID" - column ="subscriberID" + name="subscriberID" + column="subscriberID" fieldtype="id" generator="uuid" - length ="36" - ormtype ="string" - update ="false"; + length="36" + ormtype="string" + update="false"; property - name ="subscriberEmail" - column ="subscriberEmail" + name="subscriberEmail" + column="subscriberEmail" notnull="true" - length ="255" - index ="idx_subscriberEmail"; + length="255" + index="idx_subscriberEmail"; property - name ="subscriberToken" - column ="subscriberToken" + name="subscriberToken" + column="subscriberToken" ormtype="string" - length ="255" + length="255" notnull="true"; - /* ********************************************************************* - ** RELATIONSHIPS - ********************************************************************* */ + /********************************************************************** + * ** RELATIONSHIPS + **********************************************************************/ property - name ="subscriptions" + name="subscriptions" singularName="subscription" - fieldtype ="one-to-many" - type ="array" - lazy ="true" - batchsize ="25" - orderby ="createdDate" - cfc ="contentbox.models.subscriptions.BaseSubscription" - fkcolumn ="FK_subscriberID" - inverse ="true" - cascade ="all-delete-orphan"; - - /* ********************************************************************* - ** PK + CONSTRAINTS - ********************************************************************* */ + fieldtype="one-to-many" + type="array" + lazy="true" + batchsize="25" + orderby="createdDate" + cfc="contentbox.models.subscriptions.BaseSubscription" + fkcolumn="FK_subscriberID" + inverse="true" + cascade="all-delete-orphan"; + /********************************************************************** + * ** PK + CONSTRAINTS + **********************************************************************/ this.pk = "subscriberID"; this.memento = { - defaultIncludes : [ - "subscriberEmail", - "subscriptionToken", - "subscriptionsSnapshot:subscriptions" - ], - defaultExcludes : [] + defaultIncludes: [ "subscriberEmail", "subscriptionToken", "subscriptionsSnapshot:subscriptions"], + defaultExcludes: [] }; this.constraints = { - "subscriptionToken" : { required : true, size : "1..255" }, - "subscriberEmail" : { required : true, size : "1..255", type : "email" } + "subscriptionToken": { required: true, size: "1..255" }, + "subscriberEmail" : { required: true, size: "1..255", type: "email" } }; - /* ********************************************************************* - ** METHODS - ********************************************************************* */ + /********************************************************************** + * ** METHODS + **********************************************************************/ - function init(){ + function init() { super.init(); return this; } @@ -90,12 +84,12 @@ component /** * Utility method to get a snapshot of this object */ - struct function getInfoSnapshot(){ + struct function getInfoSnapshot() { if ( isLoaded() ) { return { - "subscriberID" : getSubscriberID(), - "subscriberEmail" : getSubscriberEmail(), - "subscriberToken" : getSubscriberToken() + "subscriberID" : getSubscriberID(), + "subscriberEmail": getSubscriberEmail(), + "subscriberToken": getSubscriberToken() }; } return {}; @@ -104,11 +98,13 @@ component /** * Build a snapshot of subscriptions this subscriber has */ - array function getSubscriptionsSnapshot(){ + array function getSubscriptionsSnapshot() { if ( hasSubscriptions() ) { - return getSubscriptions().map( function( thisItem ){ - return arguments.thisItem.getMemento( excludes = "subscriber" ); - } ); + return getSubscriptions().map( + function( thisItem ) { + return arguments.thisItem.getMemento( excludes = "subscriber" ); + } + ); } return {}; } @@ -116,7 +112,7 @@ component /** * Before insert create the user subscription token */ - public void function preInsert(){ + public void function preInsert() { super.preInsert(); if ( isNull( getSubscriberToken() ) ) { var tkn = getSubscriberEmail() & getCreatedDate(); @@ -127,14 +123,14 @@ component /** * Returns a slim representation of subscriptions by type */ - public struct function getSubscriptionsByContentType(){ + public struct function getSubscriptionsByContentType() { var subs = {}; for ( var subscription in getSubscriptions() ) { var contentType = subscription.getType(); if ( !structKeyExists( subs, contentType ) ) { subs[ "#contentType#" ] = []; } - var memento = { "subscriptionToken" : subscription.getSubscriptionToken() }; + var memento = { "subscriptionToken": subscription.getSubscriptionToken() }; switch ( contentType ) { case "Comment": memento[ "title" ] = subscription.getRelatedContent().getTitle(); @@ -145,4 +141,4 @@ component return subs; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/subscriptions/SubscriberService.cfc b/modules/contentbox/models/subscriptions/SubscriberService.cfc index 51f41517d1..bd79818884 100644 --- a/modules/contentbox/models/subscriptions/SubscriberService.cfc +++ b/modules/contentbox/models/subscriptions/SubscriberService.cfc @@ -7,15 +7,15 @@ */ component extends="cborm.models.VirtualEntityService" singleton { - SubscriberService function init(){ + SubscriberService function init() { // init it super.init( entityName = "cbSubscriber", useQueryCaching = true ); return this; } - numeric function getUniqueSubscriberCount(){ + numeric function getUniqueSubscriberCount() { return newCriteria().withProjections( countDistinct = "email" ).count(); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/subscriptions/SubscriptionListener.cfc b/modules/contentbox/models/subscriptions/SubscriptionListener.cfc index 5945f4409d..6bfa9eabe3 100644 --- a/modules/contentbox/models/subscriptions/SubscriptionListener.cfc +++ b/modules/contentbox/models/subscriptions/SubscriptionListener.cfc @@ -5,19 +5,23 @@ * --- * Comment Notification interceptor */ -component extends="coldbox.system.Interceptor" accessors="true" { - +component extends ="coldbox.system.Interceptor" accessors="true" { // DI property name="commentService" inject="id:commentService@contentbox"; + property name="subscriberService" inject="id:subscriberService@contentbox"; - property name="commentSubscriptionService" inject="id:commentSubscriptionService@contentbox"; - function configure(){ + property + name="commentSubscriptionService" + inject="id:commentSubscriptionService@contentbox"; + + function configure() { + } - public void function cbui_onCommentPost( required any event, required struct data ){ - var content = data.content; - var comment = data.comment; + public void function cbui_onCommentPost( required any event, required struct data ) { + var content = data.content; + var comment = data.comment; var subscribe = data.subscribe; var moderated = data.moderationResults.moderated; @@ -28,17 +32,17 @@ component extends="coldbox.system.Interceptor" accessors="true" { // if author has elected to subscribe to comments, do it if ( subscribe ) { - var criteria = { subscriberEmail : comment.getAuthorEmail() }; + var criteria = { subscriberEmail: comment.getAuthorEmail() }; var subscriber = variables.subscriberService.findWhere( criteria = criteria ); - var exists = false; + var exists = false; if ( isNull( subscriber ) ) { subscriber = variables.subscriberService.new( criteria ); } var args = { - relatedContent : comment.getRelatedContent(), - subscriber : subscriber, - type : "Comment" + relatedContent: comment.getRelatedContent(), + subscriber : subscriber, + type : "Comment" }; if ( subscriber.isLoaded() ) { exists = !isNull( commentSubscriptionService.findWhere( criteria = args ) ); @@ -52,7 +56,7 @@ component extends="coldbox.system.Interceptor" accessors="true" { } } - public void function cbadmin_onCommentStatusUpdate( required any event, required struct data ){ + public void function cbadmin_onCommentStatusUpdate( required any event, required struct data ) { var commentIds = listToArray( arguments.data.commentID ); for ( var commentId in commentIds ) { var comment = commentService.get( commentId ); @@ -62,4 +66,4 @@ component extends="coldbox.system.Interceptor" accessors="true" { } } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/subscriptions/SubscriptionService.cfc b/modules/contentbox/models/subscriptions/SubscriptionService.cfc index 1c243c3e70..0967663c35 100644 --- a/modules/contentbox/models/subscriptions/SubscriptionService.cfc +++ b/modules/contentbox/models/subscriptions/SubscriptionService.cfc @@ -7,9 +7,9 @@ */ component extends="cborm.models.VirtualEntityService" singleton { - SubscriptionService function init( entityName = "cbSubscription" ){ + SubscriptionService function init( entityName = "cbSubscription" ) { super.init( entityName = arguments.entityName, useQueryCaching = true ); return this; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/system/CBHelper.cfc b/modules/contentbox/models/system/CBHelper.cfc index 58235a45be..cca2b4de53 100644 --- a/modules/contentbox/models/system/CBHelper.cfc +++ b/modules/contentbox/models/system/CBHelper.cfc @@ -6,34 +6,53 @@ * This is the ContentBox UI helper class that is injected by the CBRequest interceptor */ component accessors="true" singleton threadSafe { - // DI property name="categoryService" inject="categoryService@contentbox"; + property name="settingService" inject="settingService@contentbox"; + property name="entryService" inject="entryService@contentbox"; + property name="pageService" inject="pageService@contentbox"; + property name="authorService" inject="authorService@contentbox"; + property name="commentService" inject="commentService@contentbox"; + property name="contentStoreService" inject="contentStoreService@contentbox"; + property name="widgetService" inject="widgetService@contentbox"; + property name="moduleService" inject="moduleService@contentbox"; + property name="themeService" inject="themeService@contentbox"; + property name="mobileDetector" inject="mobileDetector@contentbox"; + property name="menuService" inject="menuService@contentbox"; + property name="menuItemService" inject="menuItemService@contentbox"; + property name="siteService" inject="siteService@contentbox"; + property name="requestService" inject="coldbox:requestService"; + property name="wirebox" inject="wirebox"; + property name="controller" inject="coldbox"; + property name="cbResourceService" inject="resourceService@cbi18n"; + property name="securityService" inject="securityService@contentbox"; + property name="markdown" inject="Processor@cbmarkdown"; + property name="requestStorage" inject="requestStorage@cbstorages"; /** * Constructor */ - function init(){ + function init() { return this; } @@ -44,7 +63,7 @@ component accessors="true" singleton threadSafe { * * @return coldbox.system.web.context.RequestContext */ - function getRequestContext(){ + function getRequestContext() { return variables.requestService.getContext(); } @@ -53,14 +72,14 @@ component accessors="true" singleton threadSafe { * * @private The boolean bit that says give me the RC by default or true for the private collection (PRC) */ - struct function getRequestCollection( boolean private = false ){ + struct function getRequestCollection( boolean private = false ) { return getRequestContext().getCollection( private = arguments.private ); } /** * Get the private request collection */ - struct function getPrivateRequestCollection(){ + struct function getPrivateRequestCollection() { return getRequestContext().getCollection( private = true ); } @@ -69,7 +88,7 @@ component accessors="true" singleton threadSafe { * * @module The module to retrieve the configuration settings from */ - struct function getModuleSettings( required module ){ + struct function getModuleSettings( required module ) { return getModuleConfig( arguments.module ).settings; } @@ -78,15 +97,15 @@ component accessors="true" singleton threadSafe { * * @module The module to retrieve the configuration structure from */ - struct function getModuleConfig( required module ){ + struct function getModuleConfig( required module ) { var mConfig = controller.getSetting( "modules" ); if ( structKeyExists( mConfig, arguments.module ) ) { return mConfig[ arguments.module ]; } throw( - message: "The module you passed #arguments.module# is invalid.", - detail : "The loaded modules are #structKeyList( mConfig )#", - type : "FrameworkSuperType.InvalidModuleException" + message = "The module you passed #arguments.module# is invalid.", + detail = "The loaded modules are #structKeyList( mConfig )#", + type = "FrameworkSuperType.InvalidModuleException" ); } @@ -99,7 +118,7 @@ component accessors="true" singleton threadSafe { * @defaultValue The default value to return if not found * @throw InvalidSettingException */ - any function setting( required key, defaultValue ){ + any function setting( required key, defaultValue ) { var prc = getPrivateRequestCollection(); // See if all the settings are loaded, else lazy load them @@ -117,9 +136,9 @@ component accessors="true" singleton threadSafe { } // else throw exception throw( - message: "Setting requested: #arguments.key# not found", - detail : "Settings keys are #structKeyList( prc.cbSettings )#", - type : "InvalidSettingException" + message = "Setting requested: #arguments.key# not found", + detail = "Settings keys are #structKeyList( prc.cbSettings )#", + type = "InvalidSettingException" ); } @@ -131,7 +150,7 @@ component accessors="true" singleton threadSafe { * * @throws InvalidSettingException */ - any function siteSetting( required key, defaultValue ){ + any function siteSetting( required key, defaultValue ) { var prc = getPrivateRequestCollection(); // See if all the settings are loaded, else lazy load them @@ -149,44 +168,44 @@ component accessors="true" singleton threadSafe { } // else throw exception throw( - message: "Site Setting requested: #arguments.key# not found", - detail : "Site Settings keys are #structKeyList( prc.cbSiteSettings )#", - type : "InvalidSettingException" + message = "Site Setting requested: #arguments.key# not found", + detail = "Site Settings keys are #structKeyList( prc.cbSiteSettings )#", + type = "InvalidSettingException" ); } /** * The ContentBox version */ - function getContentBoxVersion(){ + function getContentBoxVersion() { return getModuleConfig( "contentbox" ).version; } /** * The ContentBox Codename */ - function getContentBoxCodeName(){ + function getContentBoxCodeName() { return getModuleSettings( "contentbox" ).codename; } /** * The ContentBox codename Uri */ - function getContentBoxCodeNameURL(){ + function getContentBoxCodeNameURL() { return getModuleSettings( "contentbox" ).codenameLink; } /** * Get the blog entry point as specified in the global settings */ - function getBlogEntryPoint(){ + function getBlogEntryPoint() { return setting( "cb_site_blog_entrypoint", "blog" ); } /** * Get the maintenance message from the ContentBox settings in rendering condition. */ - function getMaintenanceMessage(){ + function getMaintenanceMessage() { return variables.markdown.toHTML( setting( "cb_site_maintenance_message", "" ) ); } @@ -201,8 +220,8 @@ component accessors="true" singleton threadSafe { required slug, defaultValue = "", string siteID = site().getsiteID() - ){ - var content = variables.contentStoreService.findBySlug( slug: arguments.slug, siteID: arguments.siteID ); + ) { + var content = variables.contentStoreService.findBySlug( slug = arguments.slug, siteID = arguments.siteID ); // Render if the object is loaded return ( !content.isLoaded() ? arguments.defaultValue : content.renderContent() ); @@ -215,12 +234,12 @@ component accessors="true" singleton threadSafe { * * @return The content object or a new empty content object */ - function contentStoreObject( required slug, string siteID = site().getsiteID() ){ + function contentStoreObject( required slug, string siteID = site().getsiteID() ) { return contentStoreService.findBySlug( - slug : arguments.slug, - showUnpublished: true, - siteID : arguments.siteID - ); + slug = arguments.slug, + showUnpublished = true, + siteID = arguments.siteID + ); } /************************************** root and pathing methods *********************************************/ @@ -228,28 +247,28 @@ component accessors="true" singleton threadSafe { /** * Verifies if the admin module is loaded */ - function isAdminLoaded(){ + function isAdminLoaded() { return structKeyExists( controller.getSetting( "modules" ), "contentbox-admin" ); } /** * Get the admin site root location using the configured module's entry point */ - function adminRoot(){ + function adminRoot() { return getPrivateRequestCollection().cbAdminEntryPoint; } /** * Get the name of the current set and active theme */ - function themeName(){ + function themeName() { return getPrivateRequestCollection().cbTheme; } /** * Get the theme record of the current set and active theme */ - function themeRecord(){ + function themeRecord() { return getPrivateRequestCollection().cbThemeRecord; } @@ -259,7 +278,7 @@ component accessors="true" singleton threadSafe { * @key The name of the theme setting * @defaultValue The default value if the layout setting does not exist */ - function themeSetting( required key, defaultValue ){ + function themeSetting( required key, defaultValue ) { arguments.key = "cb_theme_#themeName()#_#arguments.key#"; return siteSetting( argumentCollection = arguments ); } @@ -275,14 +294,17 @@ component accessors="true" singleton threadSafe { * * @siteID The site id to get the root from, by default we use the current site you are on */ - function site( string siteID = "" ){ + function site( string siteID = "" ) { // Verify incoming override/lookup if ( len( arguments.siteID ) ) { // Do a request storage lookup cache for optmizations when requesting the same site // over and over again in the same request. - return variables.requestStorage.getOrSet( "cbhelper-request-site-#arguments.siteID#", function(){ - return variables.siteService.getOrFail( siteID ); - } ); + return variables.requestStorage.getOrSet( + "cbhelper-request-site-#arguments.siteID#", + function() { + return variables.siteService.getOrFail( siteID ); + } + ); } // Verify PRC @@ -298,7 +320,7 @@ component accessors="true" singleton threadSafe { /** * Get the location of your currently defined theme in the application, great for assets, cfincludes, etc */ - function themeRoot(){ + function themeRoot() { return getPrivateRequestCollection().cbThemeRoot; } @@ -307,7 +329,7 @@ component accessors="true" singleton threadSafe { * * @siteID The site id to get the root from, by default we use the current site you are on */ - function siteRoot( string siteID = "" ){ + function siteRoot( string siteID = "" ) { // Return the appropriate site Uri return this.site( arguments.siteID ).getSiteRoot() & getModuleConfig( "contentbox-ui" ).entryPoint; } @@ -317,7 +339,7 @@ component accessors="true" singleton threadSafe { * * @siteID The site id to get the root from, by default we use the current site you are on */ - function siteBaseURL( string siteID = "" ){ + function siteBaseURL( string siteID = "" ) { return reReplaceNoCase( this.siteRoot( arguments.siteID ), "index.cfm\/?", @@ -328,42 +350,42 @@ component accessors="true" singleton threadSafe { /** * Retrieve the site name */ - function siteName(){ + function siteName() { return site().getName(); } /** * Retrieve the site tagline */ - function siteTagLine(){ + function siteTagLine() { return site().getTagLine(); } /** * Retrieve the site description */ - function siteDescription(){ + function siteDescription() { return site().getDescription(); } /** * Retrieve the site keywords */ - function siteKeywords(){ + function siteKeywords() { return site().getKeywords(); } /** * Retrieve the site administrator email */ - function siteEmail(){ + function siteEmail() { return site().getNotificationEmails(); } /** * Retrieve the site outgoing email */ - function siteOutgoingEmail(){ + function siteOutgoingEmail() { return setting( "cb_site_outgoingEmail" ); } @@ -372,9 +394,9 @@ component accessors="true" singleton threadSafe { * * @content The entry or page content to validate comments also with */ - boolean function isCommentsEnabled( content ){ + boolean function isCommentsEnabled( content ) { if ( !isNull( arguments.content ) ) { - return ( arguments.content.getAllowComments() AND siteSetting( "cb_comments_enabled" ) ); + return ( arguments.content.getAllowComments() && siteSetting( "cb_comments_enabled" ) ); } return ( siteSetting( "cb_comments_enabled" ) ); } @@ -382,14 +404,14 @@ component accessors="true" singleton threadSafe { /** * Determines if a comment form error has ocurred */ - boolean function isCommentFormError(){ + boolean function isCommentFormError() { return getFlash().exists( "commentErrors" ); } /** * Determine if you are in printing or exporting format */ - boolean function isPrintFormat(){ + boolean function isPrintFormat() { var currentFormat = getRequestContext().getValue( "format", "contentbox" ); return ( listFindNoCase( "contentbox,html", currentFormat ) ? false : true ); } @@ -399,7 +421,7 @@ component accessors="true" singleton threadSafe { * * @return The errors array or an empty array */ - array function getCommentErrors(){ + array function getCommentErrors() { return getFlash().get( "commentErrors", [] ); } @@ -420,10 +442,10 @@ component accessors="true" singleton threadSafe { string title, string description, string keywords - ){ + ) { var event = getRequestContext(); - var prc = getPrivateRequestCollection(); - var rc = getRequestCollection(); + var prc = getPrivateRequestCollection(); + var rc = getRequestCollection(); // Request Metadata if ( structKeyExists( arguments, "title" ) ) { @@ -437,7 +459,7 @@ component accessors="true" singleton threadSafe { } // store UI module root - prc.cbRoot = getContextRoot() & event.getModuleRoot( "contentbox" ); + prc.cbRoot = getContextRoot() & event.getModuleRoot( "contentbox" ); // store module entry point prc.cbEntryPoint = getModuleConfig( "contentbox-ui" ).entryPoint; // store site entry point @@ -447,29 +469,31 @@ component accessors="true" singleton threadSafe { prc.cbAdminEntryPoint = ""; } // Place site on request - prc.oCurrentSite = variables.siteService.discoverSite(); + prc.oCurrentSite = variables.siteService.discoverSite(); // Place global cb options on scope - prc.cbSettings = variables.settingService.getAllSettings(); + prc.cbSettings = variables.settingService.getAllSettings(); prc.cbSiteSettings = variables.settingService.getAllSiteSettings( prc.oCurrentSite.getSlug() ); // Place the default layout on scope - prc.cbTheme = prc.oCurrentSite.getActiveTheme(); - prc.cbThemeRecord = variables.themeService.getThemeRecord( prc.cbTheme ); + prc.cbTheme = prc.oCurrentSite.getActiveTheme(); + prc.cbThemeRecord = variables.themeService.getThemeRecord( prc.cbTheme ); // Place layout root location - prc.cbthemeRoot = prc.cbThemeRecord.includePath; + prc.cbthemeRoot = prc.cbThemeRecord.includePath; // Place widgets root location - prc.cbWidgetRoot = prc.cbRoot & "/widgets"; + prc.cbWidgetRoot = prc.cbRoot & "/widgets"; // announce event this.event( "cbui_preRequest" ); // Do we set a layout for them already? if ( structKeyExists( arguments, "layout" ) ) { - event.setLayout( name = "#prc.cbThemeRecord.includePath#/layouts/" & arguments.layout ); + event.setLayout( + name = "#prc.cbThemeRecord.includePath#/layouts/#arguments.layout#" + ); } /************************************** FORCE SITE WIDE SSL *********************************************/ - if ( prc.oCurrentSite.getIsSSL() and !event.isSSL() ) { + if ( prc.oCurrentSite.getIsSSL() && !event.isSSL() ) { controller.relocate( event = event.getCurrentRoutedURL(), ssl = true ); } @@ -483,54 +507,56 @@ component accessors="true" singleton threadSafe { } // Determine if you have a category filter - boolean function categoryFilterExists(){ + boolean function categoryFilterExists() { var rc = getRequestCollection(); - return ( structKeyExists( rc, "category" ) AND len( rc.category ) ); + return ( structKeyExists( rc, "category" ) && len( rc.category ) ); } + // Get Category Filter - function getCategoryFilter(){ + function getCategoryFilter() { return getRequestContext().getValue( "category", "" ); } // Get Year Filter - function getYearFilter(){ + function getYearFilter() { return getRequestContext().getValue( "year", "0" ); } + // Get Month Filter - function getMonthFilter(){ + function getMonthFilter() { return getRequestContext().getValue( "month", "0" ); } + // Get Day Filter - function getDayFilter(){ + function getDayFilter() { return getRequestContext().getValue( "day", "0" ); } // Determine if you are in the blog - boolean function isBlogView(){ - if ( isIndexView() OR isEntryView() OR isArchivesView() ) { + boolean function isBlogView() { + if ( isIndexView() || isEntryView() || isArchivesView() ) { return true; } return false; } + // Determine if you are in the archives view - boolean function isArchivesView(){ + boolean function isArchivesView() { var event = getRequestContext(); - return ( event.getCurrentEvent() eq "contentbox-ui:blog.archives" ); + return ( event.getCurrentEvent() EQ "contentbox-ui:blog.archives" ); } + // Determine if you are in the index view - boolean function isIndexView(){ + boolean function isIndexView() { var event = getRequestContext(); - return ( event.getCurrentEvent() eq "contentbox-ui:blog.index" ); + return ( event.getCurrentEvent() EQ "contentbox-ui:blog.index" ); } + // Determine if you are in the entry view - boolean function isEntryView(){ + boolean function isEntryView() { var event = getRequestContext(); return ( - // If in static export, then mark as yes - event.getPrivateValue( "staticExport", false ) - OR - // In executing view - event.getCurrentEvent() eq "contentbox-ui:blog.entry" + event.getPrivateValue( "staticExport", false ) || event.getCurrentEvent() EQ "contentbox-ui:blog.entry" ); } @@ -539,20 +565,18 @@ component accessors="true" singleton threadSafe { * * @page Optional page slug to determine if you are in that page or not. */ - boolean function isPageView( page = "" ){ + boolean function isPageView( page = "" ) { var event = getRequestContext(); if ( - // If in static export, then mark as yes - event.getPrivateValue( "staticExport", false ) OR - ( - // Check if in page event - findNoCase( "contentbox-ui:page", event.getCurrentEvent() ) AND - // And page Exists - event.valueExists( "page", true ) - ) + event.getPrivateValue( "staticExport", false ) || + ( + findNoCase( "contentbox-ui:page", event.getCurrentEvent() ) && + event// And page Exists + .valueExists( "page", true ) + ) ) { // slug check - if ( len( arguments.page ) AND getCurrentPage().getSlug() eq arguments.page ) { + if ( len( arguments.page ) && getCurrentPage().getSlug() EQ arguments.page ) { return true; } else if ( !len( arguments.page ) ) { return true; @@ -565,7 +589,7 @@ component accessors="true" singleton threadSafe { /** * Determine if you're in a "preview" mode or not */ - boolean function isPreview(){ + boolean function isPreview() { return reFindNoCase( "contentbox-ui:.*preview", getRequestContext().getCurrentEvent() ) ? true : false; } @@ -576,7 +600,7 @@ component accessors="true" singleton threadSafe { * * @throws ContentBox.CBHelper.InvalidEntriesContext */ - any function getCurrentEntries(){ + any function getCurrentEntries() { var prc = getRequestCollection( private = true ); if ( structKeyExists( prc, "entries" ) ) { return prc.entries; @@ -593,7 +617,7 @@ component accessors="true" singleton threadSafe { * * @throws ContentBox.CBHelper.InvalidEntriesContext */ - numeric function getCurrentEntriesCount(){ + numeric function getCurrentEntriesCount() { var prc = getRequestCollection( private = true ); if ( structKeyExists( prc, "entriesCount" ) ) { return prc.entriesCount; @@ -612,11 +636,11 @@ component accessors="true" singleton threadSafe { * * @return array of category */ - any function getCurrentCategories( isPublic = true ){ + any function getCurrentCategories( isPublic = true ) { return variables.categoryService.search( - isPublic: ( isNull( arguments.isPublic ) ? javacast( "null", "" ) : arguments.isPublic ), - siteId : site().getSiteId() - ).categories; + isPublic = ( isNull( arguments.isPublic ) ? javacast( "null", "" ) : arguments.isPublic ), + siteId = site().getSiteId() + ).categories; } /** @@ -626,7 +650,7 @@ component accessors="true" singleton threadSafe { * * @throws ContentBox.CBHelper.InvalidEntryContext */ - any function getCurrentEntry(){ + any function getCurrentEntry() { var prc = getRequestCollection( private = true ); if ( structKeyExists( prc, "entry" ) ) { return prc.entry; @@ -645,7 +669,7 @@ component accessors="true" singleton threadSafe { * * @throws ContentBox.CBHelper.InvalidPageContext */ - any function getCurrentPage(){ + any function getCurrentPage() { var prc = getRequestCollection( private = true ); if ( structKeyExists( prc, "page" ) ) { return prc.page; @@ -664,7 +688,7 @@ component accessors="true" singleton threadSafe { * * @throws ContentBox.CBHelper.InvalidCommentContext */ - any function getCurrentComments(){ + any function getCurrentComments() { var prc = getRequestCollection( private = true ); if ( structKeyExists( prc, "comments" ) ) { return prc.comments; @@ -685,7 +709,7 @@ component accessors="true" singleton threadSafe { * * @throws ContentBox.CBHelper.InvalidCommentContext */ - numeric function getCurrentCommentsCount(){ + numeric function getCurrentCommentsCount() { var prc = getRequestCollection( private = true ); if ( structKeyExists( prc, "commentsCount" ) ) { return prc.commentsCount; @@ -700,12 +724,12 @@ component accessors="true" singleton threadSafe { /** * Get the missing page, if any, usually used in a page not found context */ - any function getMissingPage(){ + any function getMissingPage() { return getRequestContext().getValue( - name = "missingPage", - private = "true", - defaultValue = "" - ); + name = "missingPage", + private = "true", + defaultValue = "" + ); } /** @@ -713,14 +737,14 @@ component accessors="true" singleton threadSafe { * * @siteID The site id to get it from */ - any function getHomePage( string siteID = "" ){ + any function getHomePage( string siteID = "" ) { return site( arguments.siteID ).getHomepage(); } /** * Checks if the currently viewed page is the homepage. */ - boolean function isHomePage(){ + boolean function isHomePage() { var prc = getPrivateRequestCollection(); // Check if page exists if ( !structKeyExists( prc, "page" ) ) { @@ -734,7 +758,7 @@ component accessors="true" singleton threadSafe { * * @return array */ - any function getCurrentRelatedContent(){ + any function getCurrentRelatedContent() { var relatedContent = []; if ( isPageView() && getCurrentPage().hasRelatedContent() ) { relatedContent = getCurrentPage().getRelatedContent(); @@ -747,7 +771,7 @@ component accessors="true" singleton threadSafe { /** * Get the current page's or blog entries custom fields as a struct */ - struct function getCurrentCustomFields(){ + struct function getCurrentCustomFields() { if ( isPageView() ) { return getCurrentPage().getCustomFieldsAsStruct(); } else { @@ -761,7 +785,7 @@ component accessors="true" singleton threadSafe { * @key The custom field key * @defaultValue The default value to return if not found */ - any function getCustomField( required key, defaultValue ){ + any function getCustomField( required key, defaultValue ) { var fields = getCurrentCustomFields(); if ( structKeyExists( fields, arguments.key ) ) { return fields[ arguments.key ]; @@ -781,7 +805,7 @@ component accessors="true" singleton threadSafe { /** * Check the Meta struct exists in the PRC */ - function checkMetaStruct(){ + function checkMetaStruct() { var prc = getPrivateRequestCollection(); if ( !structKeyExists( prc, "meta" ) ) { prc.meta = {}; @@ -793,7 +817,7 @@ component accessors="true" singleton threadSafe { * * @title - The new title */ - function setMetaTitle( required string title ){ + function setMetaTitle( required string title ) { var prc = getPrivateRequestCollection(); checkMetaStruct(); prc.meta.title = arguments.title; @@ -802,7 +826,7 @@ component accessors="true" singleton threadSafe { /** * Get the Meta Title for the request */ - function getMetaTitle(){ + function getMetaTitle() { var prc = getPrivateRequestCollection(); checkMetaStruct(); if ( structKeyExists( prc.meta, "title" ) ) { @@ -817,7 +841,7 @@ component accessors="true" singleton threadSafe { * * @description - The new Description */ - function setMetaDescription( required string description ){ + function setMetaDescription( required string description ) { var prc = getPrivateRequestCollection(); checkMetaStruct(); prc.meta.description = arguments.description; @@ -826,7 +850,7 @@ component accessors="true" singleton threadSafe { /** * Get the Meta description for the request */ - function getMetaDescription(){ + function getMetaDescription() { var prc = getPrivateRequestCollection(); checkMetaStruct(); if ( structKeyExists( prc.meta, "description" ) ) { @@ -841,7 +865,7 @@ component accessors="true" singleton threadSafe { * * @keywords - The new Keywords */ - function setMetaKeywords( required string keywords ){ + function setMetaKeywords( required string keywords ) { var prc = getPrivateRequestCollection(); checkMetaStruct(); prc.meta.keywords = arguments.keywords; @@ -850,7 +874,7 @@ component accessors="true" singleton threadSafe { /** * Get the Meta keywords for the request */ - function getMetaKeywords(){ + function getMetaKeywords() { var prc = getPrivateRequestCollection(); checkMetaStruct(); if ( structKeyExists( prc.meta, "keywords" ) ) { @@ -863,9 +887,9 @@ component accessors="true" singleton threadSafe { /** * Get the current content metadata title according to SEO Discovery Rules */ - function getContentTitle(){ + function getContentTitle() { var oCurrentContent = ""; - var metaTitle = getMetaTitle(); + var metaTitle = getMetaTitle(); // If Meta Title is set Manually, return it if ( len( metaTitle ) ) { @@ -896,7 +920,7 @@ component accessors="true" singleton threadSafe { /** * Get the current content metadata description according to SEO discovery rules */ - function getContentDescription(){ + function getContentDescription() { var oCurrentContent = ""; var metaDescription = getMetaDescription(); @@ -917,9 +941,9 @@ component accessors="true" singleton threadSafe { // - Site Description if ( isHomePage() ) { metaDescription = oCurrentContent.getHTMLDescription(); - return len( metaDescription ) ? encodeForHTMLAttribute( metaDescription ) : encodeForHTMLAttribute( - siteDescription() - ); + return len( metaDescription ) + ? encodeForHTMLAttribute( metaDescription ) + : encodeForHTMLAttribute( siteDescription() ); } // Page/Blog Rules @@ -947,9 +971,9 @@ component accessors="true" singleton threadSafe { /** * Get the current content metadata keywords according to SEO discovery rules */ - function getContentKeywords(){ + function getContentKeywords() { var oCurrentContent = ""; - var metaKeywords = getMetaKeywords(); + var metaKeywords = getMetaKeywords(); // If Meta Keywords is set Manually, return it if ( len( metaKeywords ) ) { @@ -968,13 +992,13 @@ component accessors="true" singleton threadSafe { // - Site if ( isHomePage() ) { metaKeywords = stripWhitespace( oCurrentContent.getHTMLKeywords() ); - return len( metaKeywords ) ? encodeForHTMLAttribute( metaKeywords ) : encodeForHTMLAttribute( - siteKeywords() - ); + return len( metaKeywords ) + ? encodeForHTMLAttribute( metaKeywords ) + : encodeForHTMLAttribute( siteKeywords() ); } // in context view or global - if ( isObject( oCurrentContent ) AND len( oCurrentContent.getHTMLKeywords() ) ) { + if ( isObject( oCurrentContent ) && len( oCurrentContent.getHTMLKeywords() ) ) { return encodeForHTMLAttribute( stripWhitespace( oCurrentContent.getHTMLKeywords() ) ); } @@ -982,13 +1006,12 @@ component accessors="true" singleton threadSafe { return encodeForHTMLAttribute( siteKeywords() ); } - /** * Set the Meta Canonical URL for the request * * @url - The new url */ - function setMetaURL( required string url ){ + function setMetaURL( required string url ) { var prc = getPrivateRequestCollection(); checkMetaStruct(); prc.meta.url = arguments.url; @@ -997,7 +1020,7 @@ component accessors="true" singleton threadSafe { /** * Get the Meta Canonical URL for the request */ - function getMetaURL(){ + function getMetaURL() { var prc = getPrivateRequestCollection(); checkMetaStruct(); if ( structKeyExists( prc.meta, "url" ) ) { @@ -1007,14 +1030,13 @@ component accessors="true" singleton threadSafe { } } - /** * Get the Canonical URL based on content type */ - function getContentURL(){ - var oCurrentContent = ""; + function getContentURL() { + var oCurrentContent = ""; var oCurrentEntryPoint = ""; - var metaURL = getMetaURL(); + var metaURL = getMetaURL(); if ( len( metaURL ) ) { return metaURL; @@ -1022,15 +1044,15 @@ component accessors="true" singleton threadSafe { // Check if in page view or entry view if ( isPageView() ) { - oCurrentContent = getCurrentPage(); + oCurrentContent = getCurrentPage(); oCurrentEntryPoint = ""; } else if ( isEntryView() ) { - oCurrentContent = getCurrentEntry(); + oCurrentContent = getCurrentEntry(); oCurrentEntryPoint = setting( "cb_site_blog_entrypoint" ) & "/"; } // in context view or global - if ( isObject( oCurrentContent ) AND len( oCurrentContent.getslug() ) ) { + if ( isObject( oCurrentContent ) && len( oCurrentContent.getslug() ) ) { return siteBaseURL() & oCurrentEntryPoint & oCurrentContent.getslug(); } @@ -1042,7 +1064,7 @@ component accessors="true" singleton threadSafe { * * @imageURL - The new imageURL */ - function setMetaImageURL( required string imageURL ){ + function setMetaImageURL( required string imageURL ) { var prc = getPrivateRequestCollection(); checkMetaStruct(); prc.meta.imageURL = arguments.imageURL; @@ -1051,7 +1073,7 @@ component accessors="true" singleton threadSafe { /** * Get the Meta ImageURL for the request */ - function getMetaImageURL(){ + function getMetaImageURL() { var prc = getPrivateRequestCollection(); checkMetaStruct(); if ( structKeyExists( prc.meta, "imageURL" ) ) { @@ -1064,9 +1086,9 @@ component accessors="true" singleton threadSafe { /** * Get the Content Image URL based on content type */ - function getContentImageURL(){ + function getContentImageURL() { var oCurrentContent = ""; - var metaImageUrl = getMetaImageURL(); + var metaImageUrl = getMetaImageURL(); if ( len( metaImageURL ) ) { return metaImageURL; @@ -1080,7 +1102,7 @@ component accessors="true" singleton threadSafe { } // in context view or global - if ( isObject( oCurrentContent ) AND len( oCurrentContent.getFeaturedImageURL() ) ) { + if ( isObject( oCurrentContent ) && len( oCurrentContent.getFeaturedImageURL() ) ) { return siteBaseURL() & oCurrentContent.getFeaturedImageURL(); } @@ -1092,7 +1114,7 @@ component accessors="true" singleton threadSafe { * * @OGType - The new OGType */ - function setMetaOGType( required string OGType ){ + function setMetaOGType( required string OGType ) { var prc = getPrivateRequestCollection(); checkMetaStruct(); prc.meta.OGType = arguments.OGType; @@ -1101,7 +1123,7 @@ component accessors="true" singleton threadSafe { /** * Get the Meta OGType for the request */ - function getMetaOGType(){ + function getMetaOGType() { var prc = getPrivateRequestCollection(); checkMetaStruct(); if ( structKeyExists( prc.meta, "OGType" ) ) { @@ -1114,7 +1136,7 @@ component accessors="true" singleton threadSafe { /** * Get the Content Open Graph Type based on content type */ - function getContentOGType(){ + function getContentOGType() { var metaOGType = getMetaOGType(); if ( len( metaOGType ) ) { @@ -1136,49 +1158,58 @@ component accessors="true" singleton threadSafe { * More information: https://developers.facebook.com/docs/reference/opengraph * Best Practices: https://developers.facebook.com/docs/sharing/best-practices */ - function getOpenGraphMeta(){ - var content = ""; + function getOpenGraphMeta() { + var content = ""; // cfformat-ignore-start savecontent variable="content" { - writeOutput( "#chr( 10 )#" ); - writeOutput( "#chr( 10 )#" ); - writeOutput( "#chr( 10 )#" ); - - if ( len( getContentURL() ) ) { - writeOutput( "#chr( 10 )#" ); - } +writeOutput( +"#chr( 10 )#" +); +writeOutput( +"#chr( 10 )#" +); +writeOutput( +"#chr( 10 )#" +); + +if ( len( getContentURL() ) ) { +writeOutput( +"#chr( 10 )#" +); +} - if ( len( getContentImageURL() ) ) { - writeOutput( "#chr( 10 )#" ); - } - } +if ( len( getContentImageURL() ) ) { +writeOutput( +"#chr( 10 )#" +); +} +} // cfformat-ignore-end return content; } - /************************************** search *********************************************/ // Determine if you are in the search view - boolean function isSearchView(){ + boolean function isSearchView() { var event = getRequestContext(); - return ( event.getCurrentEvent() eq "contentbox-ui:page.search" ); + return ( event.getCurrentEvent() EQ "contentbox-ui:page.search" ); } /** * quickSearchForm will build a standard ContentBox Content Search Form according to the SearchForm widget */ - function quickSearchForm(){ - return widget( "SearchForm", { type : "content" } ); + function quickSearchForm() { + return widget( "SearchForm", { type: "content" } ); } /** * Render out paging for search content */ - function quickSearchPaging(){ + function quickSearchPaging() { var prc = getRequestCollection( private = true ); - if ( NOT structKeyExists( prc, "oPaging" ) ) { + if ( !structKeyExists( prc, "oPaging" ) ) { throw( message = "Paging object is not in the collection", detail = "This probably means you are trying to use the paging outside of the search results page and that is a No No", @@ -1186,10 +1217,10 @@ component accessors="true" singleton threadSafe { ); } return prc.oPaging.renderit( - foundRows = getSearchResults().getTotal(), - link = prc.pagingLink, - pagingMaxRows = setting( "cb_search_maxResults" ) - ); + foundRows = getSearchResults().getTotal(), + link = prc.pagingLink, + pagingMaxRows = setting( "cb_search_maxResults" ) + ); } /** @@ -1197,46 +1228,46 @@ component accessors="true" singleton threadSafe { * * @return contentbox.models.search.SearchResults */ - function getSearchResults(){ + function getSearchResults() { var event = getRequestContext(); return event.getValue( - name = "searchResults", - private = "true", - default = "" - ); + name = "searchResults", + private = "true", + default = "" + ); } /** * get the curent search results HTML content */ - any function getSearchResultsContent(){ + any function getSearchResultsContent() { var event = getRequestContext(); return event.getValue( - name = "searchResultsContent", - private = "true", - default = "" - ); + name = "searchResultsContent", + private = "true", + default = "" + ); } /** * Determine if you have a search term */ - boolean function searchTermExists(){ + boolean function searchTermExists() { var rc = getRequestCollection(); - return ( structKeyExists( rc, "q" ) AND len( rc.q ) ); + return ( structKeyExists( rc, "q" ) && len( rc.q ) ); } /** * Get Search Term used */ - function getSearchTerm(){ + function getSearchTerm() { return getRequestContext().getValue( "q", "" ); } /************************************** events *********************************************/ // event announcements, funky for whitespace reasons - function event( required state, struct data = structNew() ) output="true"{ + function event( required state, struct data = structNew() ) output="true" { controller.getInterceptorService().announce( arguments.state, arguments.data ); } @@ -1255,16 +1286,16 @@ component accessors="true" singleton threadSafe { required string to, queryString = "", boolean ssl = getRequestContext().isSSL() - ){ + ) { // Remove by 6.x if ( !isNull( arguments.linkTo ) ) { arguments.to = arguments.linkTo; } return getRequestContext().buildLink( - to : adminRoot() & ".module.#arguments.module#.#arguments.to#", - queryString: arguments.queryString, - ssl : arguments.ssl - ); + to = adminRoot() & ".module.#arguments.module#.#arguments.to#", + queryString = arguments.queryString, + ssl = arguments.ssl + ); } /** @@ -1277,13 +1308,12 @@ component accessors="true" singleton threadSafe { string URI, string queryString = "", persist, - struct persistStruct - boolean addToken, + struct persistStruct boolean addToken, boolean ssl, baseURL, boolean postProcessExempt, numeric statusCode - ){ + ) { return moduleRelocate( argumentCollection = arguments ); } @@ -1310,13 +1340,12 @@ component accessors="true" singleton threadSafe { string URI, string queryString = "", persist, - struct persistStruct - boolean addToken, + struct persistStruct boolean addToken, boolean ssl, baseURL, boolean postProcessExempt, numeric statusCode - ){ + ) { arguments.event = adminRoot() & ".module.#arguments.module#.#arguments.event#"; return controller.relocate( argumentCollection = arguments ); } @@ -1327,7 +1356,7 @@ component accessors="true" singleton threadSafe { * @event An optional event to link to * @ssl Use SSL or not, defaults to event context. */ - function linkAdmin( event = "", boolean ssl = getRequestContext().isSSL() ){ + function linkAdmin( event = "", boolean ssl = getRequestContext().isSSL() ) { return getRequestContext().buildLink( to = adminRoot() & ".#arguments.event#", ssl = arguments.ssl ); } @@ -1336,7 +1365,7 @@ component accessors="true" singleton threadSafe { * * @ssl Use SSL or not, defaults to event context. */ - function linkAdminLogout( boolean ssl = getRequestContext().isSSL() ){ + function linkAdminLogout( boolean ssl = getRequestContext().isSSL() ) { return getRequestContext().buildLink( to = adminRoot() & "/security/doLogout", ssl = arguments.ssl ); } @@ -1345,7 +1374,7 @@ component accessors="true" singleton threadSafe { * * @ssl Use SSL or not, defaults to event context. */ - function linkAdminLogin( boolean ssl = getRequestContext().isSSL() ){ + function linkAdminLogin( boolean ssl = getRequestContext().isSSL() ) { return getRequestContext().buildLink( to = adminRoot() & "/security/login", ssl = arguments.ssl ); } @@ -1354,7 +1383,7 @@ component accessors="true" singleton threadSafe { * * @siteID The site id to link to or use the default */ - function linkHome( string siteID = "" ){ + function linkHome( string siteID = "" ) { return siteRoot( arguments.siteID ); } @@ -1363,24 +1392,17 @@ component accessors="true" singleton threadSafe { * * @siteID The site id to link to or use the default */ - function linkBlog( string siteID = "" ){ + function linkBlog( string siteID = "" ) { return "#siteRoot( arguments.siteID )#/#getBlogEntryPoint()#"; } /** * Create a link to the current page/entry you are on */ - function linkSelf(){ + function linkSelf() { return "#siteRoot()##sep()##cgi.script_name##cgi.path_info#"; } - /** - * Get the site URL separator depending if you have an entry point or not - */ - private function sep(){ - return "/"; - } - /** * Link to RSS feeds that ContentBox generates, by default it is the recent updates feed * @@ -1391,10 +1413,10 @@ component accessors="true" singleton threadSafe { */ function linkRSS( category, - comments = false, + comments = false, entry, boolean ssl = getRequestContext().isSSL() - ){ + ) { var xehRSS = linkBlog() & "/rss"; // do we have a category? @@ -1428,8 +1450,8 @@ component accessors="true" singleton threadSafe { any category, boolean comments = false, string slug, - boolean ssl = getRequestContext().isSSL() - ){ + boolean ssl = getRequestContext().isSSL() + ) { var xehRSS = siteRoot() & sep() & "__rss"; // do we have a category? @@ -1466,8 +1488,8 @@ component accessors="true" singleton threadSafe { any category, boolean comments = false, page, - boolean ssl = getRequestContext().isSSL() - ){ + boolean ssl = getRequestContext().isSSL() + ) { var xehRSS = siteRoot() & sep() & "__rss/pages"; // do we have a category? @@ -1498,7 +1520,7 @@ component accessors="true" singleton threadSafe { * @category The category object or slug to link to * @ssl Use SSL or not, defaults to false. */ - function linkCategory( required any category, boolean ssl = getRequestContext().isSSL() ){ + function linkCategory( required any category, boolean ssl = getRequestContext().isSSL() ) { var categorySlug = ""; if ( isSimpleValue( arguments.category ) ) { categorySlug = arguments.category; @@ -1515,7 +1537,10 @@ component accessors="true" singleton threadSafe { * @categorySlug The category slug as a string to link to * @ssl Use SSL or not, defaults to false. */ - function linkCategoryWithSlug( required string categorySlug, boolean ssl = getRequestContext().isSSL() ){ + function linkCategoryWithSlug( + required string categorySlug, + boolean ssl = getRequestContext().isSSL() + ) { return linkBlog() & "/category/#arguments.categorySlug#"; } @@ -1527,12 +1552,7 @@ component accessors="true" singleton threadSafe { * @day The day of the archive * @ssl Use SSL or not, defaults to false. */ - function linkArchive( - year, - month, - day, - boolean ssl = getRequestContext().isSSL() - ){ + function linkArchive( year, month, day, boolean ssl = getRequestContext().isSSL() ) { var xeh = linkBlog() & "/archives"; if ( structKeyExists( arguments, "year" ) ) { @@ -1553,7 +1573,7 @@ component accessors="true" singleton threadSafe { * * @ssl Use SSL or not, defaults to false. */ - function linkSearch( boolean ssl = getRequestContext().isSSL() ){ + function linkSearch( boolean ssl = getRequestContext().isSSL() ) { return linkBlog() & "/search"; } @@ -1562,7 +1582,7 @@ component accessors="true" singleton threadSafe { * * @ssl Use SSL or not, defaults to false. */ - function linkContentSearch( boolean ssl = getRequestContext().isSSL() ){ + function linkContentSearch( boolean ssl = getRequestContext().isSSL() ) { return siteRoot() & sep() & "__search"; } @@ -1571,7 +1591,7 @@ component accessors="true" singleton threadSafe { * * @ssl Use SSL or not, defaults to false. */ - function linkContentSubscription( boolean ssl = getRequestContext().isSSL() ){ + function linkContentSubscription( boolean ssl = getRequestContext().isSSL() ) { return siteRoot() & sep() & "__subscribe"; } @@ -1580,7 +1600,7 @@ component accessors="true" singleton threadSafe { * * @token The token to use for unsubscribing */ - function linkContentUnsubscribe( required string token, boolean ssl = getRequestContext().isSSL() ){ + function linkContentUnsubscribe( required string token, boolean ssl = getRequestContext().isSSL() ) { return siteRoot() & sep() & "__unsubscribe/#arguments.token#"; } @@ -1595,9 +1615,9 @@ component accessors="true" singleton threadSafe { required entry, boolean ssl = getRequestContext().isSSL(), format = "html" - ){ + ) { // format? - var outputFormat = ( arguments.format neq "html" ? ".#arguments.format#" : "" ); + var outputFormat = ( arguments.format NEQ "html" ? ".#arguments.format#" : "" ); if ( isSimpleValue( arguments.entry ) ) { return linkEntrywithslug( @@ -1621,11 +1641,15 @@ component accessors="true" singleton threadSafe { required slug, boolean ssl = getRequestContext().isSSL(), format = "html" - ){ + ) { // format? - var outputFormat = ( arguments.format neq "html" ? ".#arguments.format#" : "" ); + var outputFormat = ( arguments.format NEQ "html" ? ".#arguments.format#" : "" ); // Cleanup - arguments.slug = reReplace( arguments.slug, "^/", "" ); + arguments.slug = reReplace( + arguments.slug, + "^/", + "" + ); // link return linkBlog() & sep() & arguments.slug & outputFormat; } @@ -1641,15 +1665,15 @@ component accessors="true" singleton threadSafe { required content, boolean ssl = getRequestContext().isSSL(), format = "html" - ){ - if ( arguments.content.getContentType() eq "entry" ) { + ) { + if ( arguments.content.getContentType() EQ "entry" ) { return linkEntry( arguments.content, arguments.ssl, arguments.format ); } - if ( arguments.content.getContentType() eq "page" ) { + if ( arguments.content.getContentType() EQ "page" ) { return linkPage( arguments.content, arguments.ssl, @@ -1671,9 +1695,9 @@ component accessors="true" singleton threadSafe { required page, boolean ssl = getRequestContext().isSSL(), format = "html" - ){ + ) { // format extension? - var outputFormat = ( arguments.format neq "html" ? ".#arguments.format#" : "" ); + var outputFormat = ( arguments.format NEQ "html" ? ".#arguments.format#" : "" ); // link directly or with slug if ( isSimpleValue( arguments.page ) ) { @@ -1699,11 +1723,15 @@ component accessors="true" singleton threadSafe { required slug, boolean ssl = getRequestContext().isSSL(), format = "html" - ){ + ) { // format? - var outputFormat = ( arguments.format neq "html" ? ".#arguments.format#" : "" ); + var outputFormat = ( arguments.format NEQ "html" ? ".#arguments.format#" : "" ); // cleanup - arguments.slug = reReplace( arguments.slug, "^/", "" ); + arguments.slug = reReplace( + arguments.slug, + "^/", + "" + ); // Return the formed link return siteRoot() & sep() & arguments.slug & outputFormat; } @@ -1714,9 +1742,15 @@ component accessors="true" singleton threadSafe { * @comment The comment to link to * @ssl Use SSL or not, defaults to false. */ - function linkComment( required comment, boolean ssl = getRequestContext().isSSL() ){ + function linkComment( required comment, boolean ssl = getRequestContext().isSSL() ) { var xeh = ""; - if ( arguments.comment.getRelatedContent().getContentType() eq "page" ) { + if ( + arguments + .comment + .getRelatedContent() + .getContentType() EQ + "page" + ) { xeh = linkPage( arguments.comment.getRelatedContent(), arguments.ssl ); } else { xeh = linkEntry( arguments.comment.getRelatedContent(), arguments.ssl ); @@ -1732,9 +1766,9 @@ component accessors="true" singleton threadSafe { * @content The entry or page to link to its comments * @ssl Use SSL or not, defaults to false. */ - function linkComments( required content, boolean ssl = getRequestContext().isSSL() ){ + function linkComments( required content, boolean ssl = getRequestContext().isSSL() ) { var xeh = ""; - if ( arguments.content.getContentType() eq "page" ) { + if ( arguments.content.getContentType() EQ "page" ) { xeh = linkPage( arguments.content, arguments.ssl ); } else { xeh = linkEntry( arguments.content, arguments.ssl ); @@ -1751,8 +1785,8 @@ component accessors="true" singleton threadSafe { * * @return The URL to submit to. */ - function linkCommentPost( required content, boolean ssl = getRequestContext().isSSL() ){ - if ( arguments.content.getContentType() eq "page" ) { + function linkCommentPost( required content, boolean ssl = getRequestContext().isSSL() ) { + if ( arguments.content.getContentType() EQ "page" ) { return siteRoot() & sep() & "__pageCommentPost"; } @@ -1764,7 +1798,7 @@ component accessors="true" singleton threadSafe { * * @lang The iso language code */ - function linkLanguageChange( string lang = "en_US" ){ + function linkLanguageChange( string lang = "en_US" ) { return getRequestContext().buildLink( "__changeLang/" & arguments.lang ); } @@ -1776,7 +1810,7 @@ component accessors="true" singleton threadSafe { * @name The name of the installed widget to execute * @args The argument collection to pass to the widget's renderIt() method */ - function widget( required name, struct args = structNew() ){ + function widget( required name, struct args = structNew() ) { return getWidget( arguments.name ).renderit( argumentCollection = arguments.args ); } @@ -1788,7 +1822,7 @@ component accessors="true" singleton threadSafe { * * @name The name of the installed widget to return */ - function getWidget( required name ){ + function getWidget( required name ) { return widgetService.getWidgetByDiscovery( arguments.name ); } @@ -1798,33 +1832,38 @@ component accessors="true" singleton threadSafe { * Create entry category links to be display usually on an entry or entry list. * @entry The entry to use to build its category links list. */ - function quickCategoryLinks( required entry ){ + function quickCategoryLinks( required entry ) { var e = arguments.entry; // check if it has categories - if ( NOT e.hasCategories() ) { + if ( !e.hasCategories() ) { return ""; } - var cats = e.getCategories(); + var cats = e.getCategories(); var catList = []; // iterate and create links - for ( var x = 1; x lte arrayLen( cats ); x++ ) { + for ( var x = 1; x LTE arrayLen( cats ); x++ ) { var link = "#cats[ x ].getCategory()#"; arrayAppend( catList, link ); } // return list of links - return replace( arrayToList( catList ), ",", ", ", "all" ); + return replace( + arrayToList( catList ), + ",", + ", ", + "all" + ); } /** * Render out paging for blog entries only */ - function quickPaging(){ + function quickPaging() { var prc = getRequestCollection( private = true ); - if ( NOT structKeyExists( prc, "oPaging" ) ) { + if ( !structKeyExists( prc, "oPaging" ) ) { throw( message = "Paging object is not in the collection", detail = "This probably means you are trying to use the paging outside of the main entries index page and that is a No No", @@ -1832,11 +1871,11 @@ component accessors="true" singleton threadSafe { ); } return prc.oPaging.renderit( - foundRows = prc.entriesCount, - link = prc.pagingLink, - aslist = true, - pagingMaxRows = setting( "cb_paging_maxentries" ) - ); + foundRows = prc.entriesCount, + link = prc.pagingLink, + aslist = true, + pagingMaxRows = setting( "cb_paging_maxentries" ) + ); } /** @@ -1850,11 +1889,9 @@ component accessors="true" singleton threadSafe { string template = "entry", string collectionAs = "entry", struct args = structNew() - ){ + ) { var entries = getCurrentEntries(); - return controller - .getRenderer() - .view( + return controller.getRenderer().view( view = "#themeName()#/templates/#arguments.template#", collection = entries, collectionAs = arguments.collectionAs, @@ -1873,11 +1910,9 @@ component accessors="true" singleton threadSafe { string template = "entry", string collectionAs = "entry", struct args = structNew() - ){ - var entries = [ getCurrentEntry() ]; - return controller - .getRenderer() - .view( + ) { + var entries = [ getCurrentEntry()]; + return controller.getRenderer().view( view = "#themeName()#/templates/#arguments.template#", collection = entries, collectionAs = arguments.collectionAs, @@ -1898,11 +1933,9 @@ component accessors="true" singleton threadSafe { string collectionAs = "category", struct args = structNew(), isPublic = true - ){ + ) { var categories = getCurrentCategories( argumentCollection = arguments ); - return controller - .getRenderer() - .view( + return controller.getRenderer().view( view = "#themeName()#/templates/#arguments.template#", collection = categories, collectionAs = arguments.collectionAs, @@ -1921,11 +1954,9 @@ component accessors="true" singleton threadSafe { string template = "relatedContent", string collectionAs = "relatedContent", struct args = structNew() - ){ + ) { var relatedContent = getCurrentRelatedContent(); - return controller - .getRenderer() - .view( + return controller.getRenderer().view( view = "#themeName()#/templates/#arguments.template#", collection = relatedContent, collectionAs = arguments.collectionAs, @@ -1936,14 +1967,16 @@ component accessors="true" singleton threadSafe { /** * Render out custom fields for the current content */ - function quickCustomFields(){ + function quickCustomFields() { var customFields = getCurrentCustomFields(); - var content = ""; + var content = ""; savecontent variable="content" { writeOutput( "
      " ); for ( var thisField in customFields ) { - writeOutput( "
    • #thisField#: #customFields[ thisField ]#
    • " ); + writeOutput( + "
    • #thisField#: #customFields[ thisField ]#
    • " + ); } writeOutput( "
    " ); } @@ -1962,11 +1995,9 @@ component accessors="true" singleton threadSafe { string template = "comment", string collectionAs = "comment", struct args = structNew() - ){ + ) { var comments = getCurrentComments(); - return controller - .getRenderer() - .view( + return controller.getRenderer().view( view = "#themeName()#/templates/#arguments.template#", collection = comments, collectionAs = arguments.collectionAs, @@ -1984,16 +2015,14 @@ component accessors="true" singleton threadSafe { required author, numeric size = 25, string class = "gravatar" - ){ + ) { var targetEmail = arguments.author; // check if simple or not - if ( NOT isSimpleValue( arguments.author ) ) { + if ( !isSimpleValue( arguments.author ) ) { targetEmail = arguments.author.getEmail(); } - return wirebox - .getInstance( "Avatar@contentbox" ) - .renderAvatar( + return wirebox.getInstance( "Avatar@contentbox" ).renderAvatar( email = targetEmail, size = arguments.size, class = arguments.class @@ -2021,12 +2050,12 @@ component accessors="true" singleton threadSafe { */ function quickView( required view, - cache = false, + cache = false, cacheTimeout, cacheLastAccessTimeout, cacheSuffix, - cacheProvider = "template", - module = "contentbox", + cacheProvider = "template", + module = "contentbox", struct args, collection, collectionAs = "", @@ -2034,8 +2063,8 @@ component accessors="true" singleton threadSafe { numeric collectionMaxRows = 0, collectionDelim = "", boolean prepostExempt = false - ){ - arguments.view = "#themeName()#/views/#arguments.view#"; + ) { + arguments.view = "#themeName()#/views/#arguments.view#"; arguments.module = themeRecord().module; return controller.getRenderer().view( argumentCollection = arguments ); } @@ -2058,7 +2087,7 @@ component accessors="true" singleton threadSafe { args = structNew(), viewModule = "", boolean prePostExempt = false - ){ + ) { arguments.layout = "#themeName()#/layouts/#arguments.layout#"; return controller.getRenderer().layout( argumentCollection = arguments ); } @@ -2068,8 +2097,8 @@ component accessors="true" singleton threadSafe { * * @content The content this comment form will be linked to, page or entry */ - function quickCommentForm( required content ){ - return widget( "CommentForm", { content : arguments.content } ); + function quickCommentForm( required content ) { + return widget( "CommentForm", { content: arguments.content } ); } /** @@ -2077,7 +2106,7 @@ component accessors="true" singleton threadSafe { * * @args */ - function mainView( struct args = structNew() ){ + function mainView( struct args = structNew() ) { return controller.getRenderer().view( view = "", args = arguments.args ); } @@ -2096,7 +2125,7 @@ component accessors="true" singleton threadSafe { required string slug, required type = "html", required array slugCache = [] - ){ + ) { var menu = variables.menuService.findBySlug( arguments.slug, site().getsiteID() ); if ( menu.isLoaded() ) { @@ -2117,13 +2146,16 @@ component accessors="true" singleton threadSafe { * @menu.doc_generic contentbox.models.menu.Menu * @slugCache The cache of menu slugs already used in this request */ - public string function buildProviderMenu( required any menu, required array slugCache = [] ){ - var listType = arguments.menu.getListType(); + public string function buildProviderMenu( + required any menu, + required array slugCache = [] + ) { + var listType = arguments.menu.getListType(); // arguments.listType = !reFindNoCase( "^(ul|ol)$", arguments.listType ) ? "
      " : arguments.listType; // set start var menuString = "<#listType# class='#arguments.menu.getMenuClass()#'>"; // now get root items - var items = arguments.menu.getRootMenuItems(); + var items = arguments.menu.getRootMenuItems(); // create cache of slugs to prevent infinite recursions arrayAppend( arguments.slugCache, menu.getSlug() ); // build out this top level @@ -2138,49 +2170,6 @@ component accessors="true" singleton threadSafe { return menuString; } - /** - * Builds out a level of a custom menu - * - * @items An array of menu items for this level - * @listType The type of list to create (derived from owning menu) - * @slugCache The cache of menu slugs already used in this request - */ - private string function buildProviderMenuLevel( - required array items, - required string listType = "ul", - required array slugCache = [], - string listClass = "" - ){ - var menuString = ""; - // loop over items to build out level - for ( var item in arguments.items ) { - var extras = { - slugCache : arguments.slugCache, - listType : arguments.listType - }; - // check that item can be added - if ( item.canDisplay( options = extras ) ) { - // get template from provider - menuString &= "
    • " & item - .getProvider() - .getDisplayTemplate( item, extras ); - // if this menu item has children... - if ( item.hasChild() ) { - // recurse, recurse, recurse! - menuString &= "<#arguments.listType# class='#arguments.listClass#'>" & - buildProviderMenuLevel( - items = item.getChildren(), - listType = arguments.listType, - slugCache = arguments.slugCache - ) & - ""; - } - menuString &= "
    • "; - } - } - return menuString; - } - /** * Render out a quick menu for root level pages * @@ -2202,16 +2191,16 @@ component accessors="true" singleton threadSafe { elementClass = "", parentClass = "parent", activeClass = "active" - ){ - arguments.showNone = false; + ) { + arguments.showNone = false; // get root pages arguments.pageRecords = pageService.findPublishedContent( - parent : "", - showInMenu: true, - siteID : site().getsiteID(), - properties: "contentID,slug,title,numberOfChildren", - sortOrder : "order ASC, publishedDate ASC" - ); + parent = "", + showInMenu = true, + siteID = site().getsiteID(), + properties = "contentID,slug,title", + sortOrder = "order ASC, publishedDate ASC" + ); // build it out return buildMenu( argumentCollection = arguments ); } @@ -2243,7 +2232,7 @@ component accessors="true" singleton threadSafe { parentClass = "parent", activeClass = "active", activeShowChildren = false - ){ + ) { // If page not passed, or empty, then use the current page if ( isNull( arguments.page ) || ( isSimpleValue( arguments.page ) && !len( arguments.page ) ) ) { arguments.page = getCurrentPage(); @@ -2257,12 +2246,12 @@ component accessors="true" singleton threadSafe { // get child pages arguments.pageRecords = pageService.findPublishedContent( - parent : page.getContentID(), - showInMenu: true, - siteID : site().getsiteID(), - properties: "contentID,slug,title,numberOfChildren", - sortOrder : "order ASC, publishedDate ASC" - ); + parent = page.getContentID(), + showInMenu = true, + siteID = site().getsiteID(), + properties = "contentID,slug,title", + sortOrder = "order ASC, publishedDate ASC" + ); // build it out return buildMenu( argumentCollection = arguments ); @@ -2274,7 +2263,7 @@ component accessors="true" singleton threadSafe { * @page Optional page to create link for, else look for current page * @text The optional text to use for the link, else it uses the page's title */ - function linkToParentPage( page, text = "" ){ + function linkToParentPage( page, text = "" ) { // verify incoming page if ( !structKeyExists( arguments, "page" ) ) { arguments.page = getCurrentPage(); @@ -2282,7 +2271,10 @@ component accessors="true" singleton threadSafe { // link if parent found. if ( arguments.page.hasParent() ) { if ( !len( arguments.text ) ) { - arguments.text = arguments.page.getParent().getTitle(); + arguments.text = arguments + .page + .getParent() + .getTitle(); } // build link return "#arguments.text#"; @@ -2296,12 +2288,13 @@ component accessors="true" singleton threadSafe { * @page Optional page to create link for, else look for current page * @separator Breadcrumb separator, defaults to '>' */ - function breadCrumbs( any page, string separator = ">" ){ + function breadCrumbs( any page, string separator = ">" ) { // verify incoming page if ( !structKeyExists( arguments, "page" ) ) { arguments.page = getCurrentPage(); } - return wirebox.getInstance( "PageBreadcrumbVisitor@contentbox-ui" ).visit( arguments.page, arguments.separator ); + return wirebox.getInstance( "PageBreadcrumbVisitor@contentbox-ui" ).visit( arguments.page, + arguments.separator ); } /************************************** UTILITIES *********************************************/ @@ -2309,14 +2302,14 @@ component accessors="true" singleton threadSafe { /** * Detects if the incoming request is from a mobile device or NOT. */ - boolean function isMobile(){ + boolean function isMobile() { return mobileDetector.isMobile(); } /** * Return the current system flash scope */ - any function getFlash(){ + any function getFlash() { return controller.getRequestService().getFlashScope(); } @@ -2335,10 +2328,10 @@ component accessors="true" singleton threadSafe { string locale, any values, string bundle - ){ + ) { // check for resource@bundle convention: if ( find( "@", arguments.resource ) ) { - arguments.bundle = listLast( arguments.resource, "@" ); + arguments.bundle = listLast( arguments.resource, "@" ); arguments.resource = listFirst( arguments.resource, "@" ); } return variables.cbResourceService.getResource( argumentCollection = arguments ); @@ -2347,16 +2340,82 @@ component accessors="true" singleton threadSafe { /** * utility to strip HTML */ - function stripHTML( required stringTarget ){ - return encodeForHTML( reReplaceNoCase( arguments.stringTarget, "<[^>]*>", "", "ALL" ) ); + function stripHTML( required stringTarget ) { + return encodeForHTML( + reReplaceNoCase( + arguments.stringTarget, + "<[^>]*>", + "", + "ALL" + ) + ); } /** * removes CR LF TAB double spaces from string */ - function stripWhitespace( required stringTarget ){ - arguments.stringTarget = reReplace( arguments.stringTarget, "\s", " ", "ALL" ); - return trim( reReplace( arguments.stringTarget, "\s{2,}", " ", "ALL" ) ); + function stripWhitespace( required stringTarget ) { + arguments.stringTarget = reReplace( + arguments.stringTarget, + "\s", + " ", + "ALL" + ); + return trim( + reReplace( + arguments.stringTarget, + "\s{2,}", + " ", + "ALL" + ) + ); + } + + /** + * Get the site URL separator depending if you have an entry point or not + */ + private function sep() { + return "/"; + } + + /** + * Builds out a level of a custom menu + * + * @items An array of menu items for this level + * @listType The type of list to create (derived from owning menu) + * @slugCache The cache of menu slugs already used in this request + */ + private string function buildProviderMenuLevel( + required array items, + required string listType = "ul", + required array slugCache = [], + string listClass = "" + ) { + var menuString = ""; + // loop over items to build out level + for ( var item in arguments.items ) { + var extras = { + slugCache: arguments.slugCache, + listType : arguments.listType + }; + // check that item can be added + if ( item.canDisplay( options = extras ) ) { + // get template from provider + menuString &= "
    • #item.getProvider().getDisplayTemplate( item, + extras )#"; + // if this menu item has children... + if ( item.hasChild() ) { + // recurse, recurse, recurse! + menuString &= "<#arguments.listType# class='#arguments.listClass#'>#buildProviderMenuLevel( + items = item.getChildren(), + listType = arguments.listType, + slugCache = arguments.slugCache + )##""#"; + } + menuString &= "
    • "; + } + } + return menuString; } /************************************** PRIVATE *********************************************/ @@ -2374,34 +2433,34 @@ component accessors="true" singleton threadSafe { parentClass = "parent", activeClass = "active", activeShowChildren = false - ){ + ) { // Levels = *, then create big enough integer - if ( arguments.levels eq "*" ) { + if ( arguments.levels EQ "*" ) { arguments.levels = "999999"; } // check type? if ( !reFindNoCase( "^(ul|ol|li|data|none)$", arguments.type ) ) { arguments.type = "ul"; } - var pageResults = arguments.pageRecords; + var pageResults = arguments.pageRecords; // buffer - var b = createObject( "java", "java.lang.StringBuilder" ).init( "" ); + var b = createObject( "java", "java.lang.StringBuilder" ).init( "" ); // current page? - var prc = getRequestCollection( private = true ); + var prc = getRequestCollection( private = true ); var pageAncestorContentIDs = ""; - var locPage = ""; + var locPage = ""; // class text - var classtext = []; - var currentPageID = 0; + var classtext = []; + var currentPageID = 0; // Get contentID - if ( structKeyExists( prc, "page" ) and prc.page.isLoaded() ) { - locPage = getCurrentPage(); - currentPageID = locPage.getContentID(); + if ( structKeyExists( prc, "page" ) && prc.page.isLoaded() ) { + locPage = getCurrentPage(); + currentPageID = locPage.getContentID(); pageAncestorContentIDs = locPage.getContentID(); // If this is subnav, add ancestry trail while ( locPage.hasParent() ) { - locPage = locPage.getParent(); + locPage = locPage.getParent(); pageAncestorContentIDs = listAppend( pageAncestorContentIDs, locPage.getContentID() ); } } @@ -2411,25 +2470,28 @@ component accessors="true" singleton threadSafe { b.append( "<#arguments.type# class=""#arguments.typeClass#"">" ); } // data setup - if ( arguments.type eq "data" ) { + if ( arguments.type EQ "data" ) { var dataMenu = []; } // Iterate through pages and create sub menus - for ( var x = 1; x lte pageResults.count; x++ ) { + for ( var x = 1; x LTE pageResults.count; x++ ) { // Build up the element class into the current classText array list if ( isSimpleValue( arguments.elementClass ) ) { arguments.elementClass = listToArray( arguments.elementClass ); } classText = duplicate( arguments.elementClass ); - if ( !len( arguments.excludes ) OR !listFindNoCase( arguments.excludes, pageResults.content[ x ][ "title" ] ) ) { - // Do we need to nest? + if ( + !len( arguments.excludes ) || !listFindNoCase( arguments.excludes, pageResults.content[ x ][ "title" ] ) + ) { + // Do we need to nest? Check if page has children by fetching the entity + var thisPage = pageService.get( pageResults.content[ x ][ "contentID" ] ); var doNesting = ( - arguments.currentLevel lt arguments.levels AND pageResults.content[ x ][ "numberOfChildren" ] > 0 + arguments.currentLevel LT arguments.levels && !isNull( thisPage ) && thisPage.hasChild() ); // Is element active (or one of its decendants) - var isElementActive = currentPageID eq pageResults.content[ x ][ "contentID" ]; + var isElementActive = currentPageID EQ pageResults.content[ x ][ "contentID" ]; var isElementActiveAncestor = ( listFindNoCase( pageAncestorContentIDs, pageResults.content[ x ][ "contentID" ] ) ); @@ -2439,89 +2501,91 @@ component accessors="true" singleton threadSafe { } // list - if ( arguments.type neq "none" and arguments.type neq "data" ) { + if ( arguments.type NEQ "none" && arguments.type NEQ "data" ) { // Nested Levels? if ( doNesting ) { // Setup Parent class, we are going down the wormhole arrayAppend( classText, arguments.parentClass ); // Start Embedded List b.append( - "
    • #pageResults.content[ x ][ "title" ]#" - ); + "
    • #pageResults.content[ x ][ "title" ]#" + ); // If type is "li" then guess to do a nested ul list b.append( - buildMenu( - pageRecords = pageService.findPublishedContent( - parent : pageResults.content[ x ][ "contentID" ], - showInMenu: true, - siteID : site().getsiteID(), - properties: "contentID,slug,title,numberOfChildren", - sortOrder : "order ASC, publishedDate ASC" - ), - excludes = arguments.excludes, - type = ( arguments.type eq "li" ? "ul" : arguments.type ), - typeClass = arguments.typeClass, - elementClass = arguments.elementClass, - showNone = arguments.showNone, - levels = arguments.levels, - currentLevel = arguments.currentLevel + 1, - activeShowChildren = arguments.activeShowChildren - ) - ); - } - // Do we nest active and activeShowChildren flag is activated? - else if ( - activeShowChildren AND ( isElementActive OR isElementActiveAncestor ) AND pageResults.content[ x ].hasChild() + buildMenu( + pageRecords = pageService.findPublishedContent( + parent = pageResults.content[ x ][ "contentID" ], + showInMenu = true, + siteID = site().getsiteID(), + properties = "contentID,slug,title", + sortOrder = "order ASC, publishedDate ASC" + ), + excludes = arguments.excludes, + type = ( arguments.type EQ "li" ? "ul" : arguments.type ), + typeClass = arguments.typeClass, + elementClass = arguments.elementClass, + showNone = arguments.showNone, + levels = arguments.levels, + currentLevel = arguments.currentLevel + 1, + activeShowChildren = arguments.activeShowChildren + ) + ); + } else if ( + activeShowChildren && ( isElementActive || isElementActiveAncestor ) && + pageResults.content[ x ].hasChild() ) { // Setup Parent class, we are going down the wormhole arrayAppend( classText, arguments.parentClass ); // Start Embedded List b.append( - "
    • #pageResults.content[ x ][ "title" ]#" - ); + "
    • #pageResults.content[ x ][ "title" ]#" + ); // If type is "li" then guess to do a nested ul list b.append( - buildMenu( - pageRecords = pageService.findPublishedContent( - parent : pageResults.content[ x ][ "contentID" ], - showInMenu: true, - siteID : site().getsiteID(), - properties: "contentID,slug,title,numberOfChildren", - sortOrder : "order ASC, publishedDate ASC" - ), - excludes = arguments.excludes, - type = ( arguments.type eq "li" ? "ul" : arguments.type ), - typeClass = arguments.typeClass, - showNone = arguments.showNone, - levels = 1, - elementClass = arguments.elementClass, - currentLevel = arguments.currentLevel + 1, - activeShowChildren = activeShowChildren - ) - ); + buildMenu( + pageRecords = pageService.findPublishedContent( + parent = pageResults.content[ x ][ "contentID" ], + showInMenu = true, + siteID = site().getsiteID(), + properties = "contentID,slug,title", + sortOrder = "order ASC, publishedDate ASC" + ), + excludes = arguments.excludes, + type = ( arguments.type EQ "li" ? "ul" : arguments.type ), + typeClass = arguments.typeClass, + showNone = arguments.showNone, + levels = 1, + elementClass = arguments.elementClass, + currentLevel = arguments.currentLevel + 1, + activeShowChildren = activeShowChildren + ) + ); } else { // Start Embedded List b.append( - "
    • #pageResults.content[ x ][ "title" ]#" - ); + "
    • #pageResults.content[ x ][ "title" ]#" + ); } // Close it b.append( "
    • " ); - } else if ( arguments.type eq "data" ) { + } else if ( arguments.type EQ "data" ) { var pageData = { - title : pageResults.content[ x ][ "title" ], - link : linkPageWithSlug( pageResults.content[ x ][ "slug" ] ) + title: pageResults.content[ x ][ "title" ], + link : linkPageWithSlug( pageResults.content[ x ][ "slug" ] ) }; if ( doNesting ) { pageData.subPageMenu = buildMenu( - pageRecords = pageService.findPublishedContent( - parent : pageResults.content[ x ][ "contentID" ], - showInMenu: true, - siteID : site().getsiteID(), - properties: "contentID,slug,title,numberOfChildren", - sortOrder : "order ASC, publishedDate ASC" - ), + pageRecords = pageService.findPublishedContent( + parent = pageResults.content[ x ][ "contentID" ], + showInMenu = true, + siteID = site().getsiteID(), + properties = "contentID,slug,title", + sortOrder = "order ASC, publishedDate ASC" + ), excludes = arguments.excludes, type = arguments.type, typeClass = arguments.typeClass, @@ -2531,19 +2595,15 @@ component accessors="true" singleton threadSafe { currentLevel = arguments.currentLevel + 1, activeShowChildren = arguments.activeShowChildren ); - } - // Do we nest active and activeShowChildren flag is activated? - else if ( - activeShowChildren AND isElementActive AND pageResults.content[ x ][ "numberOfChildren" ] > 0 - ) { + } else if ( activeShowChildren && isElementActive && !isNull( thisPage ) && thisPage.hasChild() ) { pageData.subPageMenu = buildMenu( - pageRecords = pageService.findPublishedContent( - parent : pageResults.content[ x ][ "contentID" ], - showInMenu: true, - siteID : site().getsiteID(), - properties: "contentID,slug,title,numberOfChildren", - sortOrder : "order ASC, publishedDate ASC" - ), + pageRecords = pageService.findPublishedContent( + parent = pageResults.content[ x ][ "contentID" ], + showInMenu = true, + siteID = site().getsiteID(), + properties = "contentID,slug,title", + sortOrder = "order ASC, publishedDate ASC" + ), excludes = arguments.excludes, type = arguments.type, typeClass = arguments.typeClass, @@ -2557,18 +2617,19 @@ component accessors="true" singleton threadSafe { arrayAppend( dataMenu, pageData ); } else { b.append( - "#pageResults.content[ x ][ "title" ]##arguments.separator#" - ); + "#pageResults.content[ x ][ "title" ]##arguments.separator#" + ); } } } - if ( arguments.type eq "data" ) { + if ( arguments.type EQ "data" ) { return dataMenu; } // None? - if ( pageResults.count eq 0 and arguments.showNone ) { + if ( pageResults.count EQ 0 && arguments.showNone ) { b.append( "
    • No Sub Pages
    • " ); } @@ -2581,4 +2642,4 @@ component accessors="true" singleton threadSafe { return b.toString(); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/system/EmailTemplateHelper.cfc b/modules/contentbox/models/system/EmailTemplateHelper.cfc index d7c101cce5..05321de3d0 100644 --- a/modules/contentbox/models/system/EmailTemplateHelper.cfc +++ b/modules/contentbox/models/system/EmailTemplateHelper.cfc @@ -6,20 +6,19 @@ * A helper to create standard email template sections */ component singleton { - // DI property name="avatar" inject="Avatar@contentbox"; /** - * Constructor + * Constructor */ - EmailTemplateHelper function init(){ + EmailTemplateHelper function init() { // Return instance return this; } - public string function author( required string email, required string content ){ - var gravatar = variables.avatar.renderAvatar( email = arguments.email, size = 40 ); + public string function author( required string email, required string content ) { + var gravatar = variables.avatar.renderAvatar( email = arguments.email, size = 40 ); savecontent variable="authorContent" { writeOutput( text( @@ -56,31 +55,33 @@ component singleton { required string borderColor = "DDDDDD", required string borderStyle = "solid", required numeric borderWidth = 1 - ){ + ) { // cfformat-ignore-start - savecontent variable="dividerContent" { - writeoutput(' - - - - - - -
      - - - - - - -
      - -
      -
      - '); - } + savecontent variable="dividerContent" { +writeoutput( +" + + + + + + +
      + + + + + + +
      + +
      +
      + " +); +} // cfformat-ignore-end -return dividerContent; + return dividerContent; } /** @@ -96,19 +97,19 @@ return dividerContent; required string level = "h2", required string color = "777", required numeric fontSize = 20 - ){ + ) { // cfformat-ignore-start - savecontent variable="headingContent" { - writeoutput(' - <#arguments.level# style="color: ###arguments.color#; display: block; font-family: Helvetica; font-size: #arguments.fontSize#px; font-style: normal; font-weight: bold; line-height: 110%; letter-spacing: normal; margin: 0; margin-bottom: 9px; text-align: left"> - #arguments.content# - - '); - } + savecontent variable="headingContent" { +writeoutput( +" + <#arguments.level# style=""color: ###arguments.color#; display: block; font-family: Helvetica; font-size: #arguments.fontSize#px; font-style: normal; font-weight: bold; line-height: 110%; letter-spacing: normal; margin: 0; margin-bottom: 9px; text-align: left""> + #arguments.content# + + " +); +} // cfformat-ignore-end -return text( - headingContent - ); + return text( headingContent ); } /** @@ -117,41 +118,50 @@ return text( * @content.hint Content for the text area * @callout.hint If true, will wrap content in a callout box */ - public string function text( required string content, required boolean callout = false ){ + public string function text( + required string content, + required boolean callout = false + ) { // cfformat-ignore-start - savecontent variable="textContent" { - writeoutput(' - - - - - - -
      - - - - - - -
      - '); - if( arguments.callout ) { - writeoutput( ' -
      - '); - } - writeoutput( '#arguments.content#' ); - if( arguments.callout ) { - writeoutput( '
      ' ); - } - writeoutput(' -
      -
      - '); - } + savecontent variable="textContent" { +writeoutput( +" + + + + + + +
      + + + + + + +
      + " +); +if ( arguments.callout ) { +writeoutput( +" +
      + " +); +} +writeoutput( "#arguments.content#" ); +if ( arguments.callout ) { +writeoutput( "
      " ); +} +writeoutput( +" +
      +
      + " +); +} // cfformat-ignore-end -return textContent; + return textContent; } /** @@ -159,69 +169,85 @@ return textContent; * * @buttons.hint Array of buttons to add to the button bar */ - public string function buttonBar( required Array buttons ){ + public string function buttonBar( required Array buttons ) { // cfformat-ignore-start - savecontent variable="buttonBarContent" { - writeoutput(' - #divider( 18, 18, 5, 18 )# - - - - - - -
      - - - - - - -
      - - - - - - -
      - '); - // loop over buttons - for( var button in arguments.buttons ) { - writeoutput(' - - - - - - - - - -
      - #button.text# -
      - #button.text# -
      - - - - - - -
       
      - '); - } - // close off bar - writeoutput(' -
      -
      -
      - #divider( 0, 18, 18, 18 )# - '); - } + savecontent variable="buttonBarContent" { +writeoutput( +" + #divider( +18, +18, +5, +18 +)# + + + + + + +
      + + + + + + +
      + + + + + + +
      + " +); +// loop over buttons +for ( var button in arguments.buttons ) { +writeoutput( +" + + + + + + + + + +
      + +
      + #button.text# +
      + + + + + + +
       
      + " +); +} +// close off bar +writeoutput( +" +
      +
      +
      + #divider( +0, +18, +18, +18 +)# + " +); +} // cfformat-ignore-end -return buttonBarContent; + return buttonBarContent; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/system/EmailTemplateService.cfc b/modules/contentbox/models/system/EmailTemplateService.cfc index 73399e4614..d763c7ca2f 100644 --- a/modules/contentbox/models/system/EmailTemplateService.cfc +++ b/modules/contentbox/models/system/EmailTemplateService.cfc @@ -1,37 +1,37 @@ -/** -******************************************************************************** -ContentBox - A Modular Content Platform -Copyright 2012 by Luis Majano and Ortus Solutions, Corp -www.ortussolutions.com -******************************************************************************** -Apache License, Version 2.0 - -Copyright Since [2012] [Luis Majano and Ortus Solutions,Corp] - -Licensed under the Apache License, Version 2.0 (the "License" ); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -******************************************************************************** -* Manage the system's email templates for admin purposes -*/ +/** + * ******************************************************************************** + * ContentBox - A Modular Content Platform + * Copyright 2012 by Luis Majano and Ortus Solutions, Corp + * www.ortussolutions.com + * ******************************************************************************** + * Apache License, Version 2.0 + * + * Copyright Since [2012] [Luis Majano and Ortus Solutions,Corp] + * + * Licensed under the Apache License, Version 2.0 (the "License" ); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ******************************************************************************** + * Manage the system's email templates for admin purposes + */ component accessors="true" singleton { - // Dependecnies property name="moduleSettings" inject="coldbox:setting:modules"; + property name="log" inject="logbox:logger:{this}"; // Local properties property name="templatesPath" type="string"; - EmailTemplateService function init(){ + EmailTemplateService function init() { templatesPath = ""; return this; } @@ -39,21 +39,21 @@ component accessors="true" singleton { /** * onDIComplete */ - function onDIComplete(){ + function onDIComplete() { setTemplatesPath( moduleSettings[ "contentbox" ].path & "/email_templates" ); } /** * Check if template exists */ - boolean function templateExists( required string name ){ + boolean function templateExists( required string name ) { return fileExists( getTemplatesPath() & "/#arguments.name#.cfm" ); } /** * Get installed templates */ - query function getTemplates(){ + query function getTemplates() { var templates = directoryList( getTemplatesPath(), false, @@ -64,4 +64,4 @@ component accessors="true" singleton { return templates; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/system/EventHandler.cfc b/modules/contentbox/models/system/EventHandler.cfc index daee5cfc02..e0ce9cc119 100644 --- a/modules/contentbox/models/system/EventHandler.cfc +++ b/modules/contentbox/models/system/EventHandler.cfc @@ -1,37 +1,36 @@ /** -******************************************************************************** -ContentBox - A Modular Content Platform -Copyright 2012 by Luis Majano and Ortus Solutions, Corp -www.ortussolutions.com -******************************************************************************** -Apache License, Version 2.0 - -Copyright Since [2012] [Luis Majano and Ortus Solutions,Corp] - -Licensed under the Apache License, Version 2.0 (the "License" ); -you may not use this file except in compliance with the License. -You may obtain a copy of the License at - -http://www.apache.org/licenses/LICENSE-2.0 - -Unless required by applicable law or agreed to in writing, software -distributed under the License is distributed on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -See the License for the specific language governing permissions and -limitations under the License. -******************************************************************************** -******************************************************************************** -Copyright Since 2005 ColdBox Framework by Luis Majano and Ortus Solutions, Corp -www.coldbox.org | www.luismajano.com | www.ortussolutions.com -******************************************************************************** - -Author : Luis Majano -Date : 10/16/2007 -Description : - A ColdBox Enabled Hibernate Event Handler that ties to the ColdBox proxy for ColdBox Operations. - -*/ + * ******************************************************************************** + * ContentBox - A Modular Content Platform + * Copyright 2012 by Luis Majano and Ortus Solutions, Corp + * www.ortussolutions.com + * ******************************************************************************** + * Apache License, Version 2.0 + * + * Copyright Since [2012] [Luis Majano and Ortus Solutions,Corp] + * + * Licensed under the Apache License, Version 2.0 (the "License" ); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * ******************************************************************************** + * ******************************************************************************** + * Copyright Since 2005 ColdBox Framework by Luis Majano and Ortus Solutions, Corp + * www.coldbox.org | www.luismajano.com | www.ortussolutions.com + * ******************************************************************************** + * + * Author : Luis Majano + * Date : 10/16/2007 + * Description : + * A ColdBox Enabled Hibernate Event Handler that ties to the ColdBox proxy for ColdBox Operations. + * + */ component extends="cborm.models.EventHandler" { - -} +} \ No newline at end of file diff --git a/modules/contentbox/models/system/NotificationService.cfc b/modules/contentbox/models/system/NotificationService.cfc index 4e0bff9b0d..1a79fe1599 100755 --- a/modules/contentbox/models/system/NotificationService.cfc +++ b/modules/contentbox/models/system/NotificationService.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -10,20 +10,25 @@ * - Page Saving and removals * - ContentStore saving and removals */ -component extends="coldbox.system.Interceptor" accessors="true" { - +component extends ="coldbox.system.Interceptor" accessors="true" { // DI property name="settingService" inject="settingService@contentbox"; + property name="siteService" inject="siteService@contentbox"; + property name="securityService" inject="securityService@contentbox"; + property name="mailService" inject="mailService@cbmailservices"; + property name="renderer" inject="coldbox:renderer"; + property name="CBHelper" inject="CBHelper@contentbox"; /** * Configure the Service */ - function configure(){ + function configure() { + } /** @@ -33,54 +38,54 @@ component extends="coldbox.system.Interceptor" accessors="true" { * @data Intercept Data * @buffer Output buffer */ - function cbadmin_postNewAuthorSave( event, data, buffer ){ - var author = arguments.data.author; + function cbadmin_postNewAuthorSave( event, data, buffer ) { + var author = arguments.data.author; var settings = variables.settingService.getAllSettings(); // Only new authors are announced, not updates, and also verify author notifications are online. - if ( NOT settings.cb_notify_author ) { + if ( !settings.cb_notify_author ) { return; } // get current logged in author performing the action var currentAuthor = variables.securityService.getAuthorSession(); - var defaultSite = variables.siteService.getDefaultSite(); + var defaultSite = variables.siteService.getDefaultSite(); // get mail payload var bodyTokens = { - authorName : author.getFullName(), - authorRole : author.getRole().getRole(), - permissionGroups : author.getPermissionGroupsList(), - authorEmail : author.getEmail(), - authorURL : CBHelper.linkAdmin( - event = "authors.editor.authorID.#author.getAuthorID()#", - ssl = settings.cb_admin_ssl - ), - currentAuthor : currentauthor.getFullName(), - currentAuthorEmail : currentAuthor.getEmail() + authorName : author.getFullName(), + authorRole : author.getRole().getRole(), + permissionGroups: author.getPermissionGroupsList(), + authorEmail : author.getEmail(), + authorURL : CBHelper.linkAdmin( + event = "authors.editor.authorID.#author.getAuthorID()#", + ssl = settings.cb_admin_ssl + ), + currentAuthor : currentauthor.getFullName(), + currentAuthorEmail: currentAuthor.getEmail() }; var mail = variables.mailservice.newMail( - to = settings.cb_site_email, - from = settings.cb_site_outgoingEmail, - subject = "#defaultSite.getName()# - Author Created - #bodyTokens.authorName#", - bodyTokens = bodyTokens, - type = "html", - server = settings.cb_site_mail_server, - username = settings.cb_site_mail_username, - password = settings.cb_site_mail_password, - port = settings.cb_site_mail_smtp, - useTLS = settings.cb_site_mail_tls, - useSSL = settings.cb_site_mail_ssl - ); + to = settings.cb_site_email, + from = settings.cb_site_outgoingEmail, + subject = "#defaultSite.getName()# - Author Created - #bodyTokens.authorName#", + bodyTokens = bodyTokens, + type = "html", + server = settings.cb_site_mail_server, + username = settings.cb_site_mail_username, + password = settings.cb_site_mail_password, + port = settings.cb_site_mail_smtp, + useTLS = settings.cb_site_mail_tls, + useSSL = settings.cb_site_mail_ssl + ); // generate content for email from template mail.setBody( - renderer.layout( - view = "/contentbox/email_templates/author_new", - layout = "/contentbox/email_templates/layouts/email", - args = { gravatarEmail : currentAuthor.getEmail() } - ) - ); + renderer.layout( + view = "/contentbox/email_templates/author_new", + layout = "/contentbox/email_templates/layouts/email", + args = { gravatarEmail: currentAuthor.getEmail() } + ) + ); // send it out variables.mailService.send( mail ); @@ -93,50 +98,50 @@ component extends="coldbox.system.Interceptor" accessors="true" { * @data Intercept Data * @buffer Output buffer */ - function cbadmin_preAuthorRemove( event, data, buffer ){ - var author = arguments.data.author; + function cbadmin_preAuthorRemove( event, data, buffer ) { + var author = arguments.data.author; // Get settings var settings = variables.settingService.getAllSettings(); // Only notify when enabled. - if ( NOT settings.cb_notify_author ) { + if ( !settings.cb_notify_author ) { return; } // get current logged in author performing the action var currentAuthor = variables.securityService.getAuthorSession(); - var defaultSite = variables.siteService.getDefaultSite(); + var defaultSite = variables.siteService.getDefaultSite(); // get mail payload var bodyTokens = { - authorName : author.getFullName(), - authorRole : author.getRole().getRole(), - authorEmail : author.getEmail(), - currentAuthor : currentauthor.getFullName(), - currentAuthorEmail : currentAuthor.getEmail() + authorName : author.getFullName(), + authorRole : author.getRole().getRole(), + authorEmail : author.getEmail(), + currentAuthor : currentauthor.getFullName(), + currentAuthorEmail: currentAuthor.getEmail() }; var mail = variables.mailservice.newMail( - to = settings.cb_site_email, - from = settings.cb_site_outgoingEmail, - subject = "#defaultSite.getName()# - Author Removed - #bodyTokens.authorName#", - bodyTokens = bodyTokens, - type = "html", - server = settings.cb_site_mail_server, - username = settings.cb_site_mail_username, - password = settings.cb_site_mail_password, - port = settings.cb_site_mail_smtp, - useTLS = settings.cb_site_mail_tls, - useSSL = settings.cb_site_mail_ssl - ); + to = settings.cb_site_email, + from = settings.cb_site_outgoingEmail, + subject = "#defaultSite.getName()# - Author Removed - #bodyTokens.authorName#", + bodyTokens = bodyTokens, + type = "html", + server = settings.cb_site_mail_server, + username = settings.cb_site_mail_username, + password = settings.cb_site_mail_password, + port = settings.cb_site_mail_smtp, + useTLS = settings.cb_site_mail_tls, + useSSL = settings.cb_site_mail_ssl + ); // generate content for email from template mail.setBody( - renderer.layout( - view = "/contentbox/email_templates/author_remove", - layout = "/contentbox/email_templates/layouts/email", - args = { gravatarEmail : currentAuthor.getEmail() } - ) - ); + renderer.layout( + view = "/contentbox/email_templates/author_remove", + layout = "/contentbox/email_templates/layouts/email", + args = { gravatarEmail: currentAuthor.getEmail() } + ) + ); // send it out variables.mailService.send( mail ); } @@ -148,15 +153,15 @@ component extends="coldbox.system.Interceptor" accessors="true" { * @data Intercept Data * @buffer Output buffer */ - function cbadmin_postEntrySave( event, data, buffer ){ + function cbadmin_postEntrySave( event, data, buffer ) { // Only new entries are announced, not updates, and also verify entry notifications are online. - if ( NOT arguments.data.isNew ) { + if ( !arguments.data.isNew ) { return; } // Setup the entry + site - var entry = arguments.data.content; - var site = entry.getSite(); + var entry = arguments.data.content; + var site = entry.getSite(); var settings = variables.settingService.getAllSettings(); // Only notify when enabled. @@ -169,14 +174,14 @@ component extends="coldbox.system.Interceptor" accessors="true" { // get mail payload var bodyTokens = { - entryTitle : entry.getTitle(), - entryExcerpt : "", - entryURL : CBHelper.linkEntry( entry = entry, ssl = site.getIsSSL() ), - entryAuthor : currentauthor.getFullName(), - entryAuthorEmail : currentAuthor.getEmail(), - entryIsPublished : entry.getIsPublished(), - entryPublishedDate : entry.getDisplayPublishedDate(), - entryExpireDate : entry.getDisplayExpireDate() + entryTitle : entry.getTitle(), + entryExcerpt : "", + entryURL : CBHelper.linkEntry( entry = entry, ssl = site.getIsSSL() ), + entryAuthor : currentauthor.getFullName(), + entryAuthorEmail : currentAuthor.getEmail(), + entryIsPublished : entry.getIsPublished(), + entryPublishedDate: entry.getDisplayPublishedDate(), + entryExpireDate : entry.getDisplayExpireDate() }; if ( entry.hasExcerpt() ) { @@ -186,27 +191,27 @@ component extends="coldbox.system.Interceptor" accessors="true" { } var mail = variables.mailservice.newMail( - to : getNotifiers( site, settings ), - from : settings.cb_site_outgoingEmail, - subject : "#site.getName()# - Blog Entry Created - #bodyTokens.entryTitle#", - bodyTokens: bodyTokens, - type : "html", - server : settings.cb_site_mail_server, - username : settings.cb_site_mail_username, - password : settings.cb_site_mail_password, - port : settings.cb_site_mail_smtp, - useTLS : settings.cb_site_mail_tls, - useSSL : settings.cb_site_mail_ssl - ); + to = getNotifiers( site, settings ), + from = settings.cb_site_outgoingEmail, + subject = "#site.getName()# - Blog Entry Created - #bodyTokens.entryTitle#", + bodyTokens = bodyTokens, + type = "html", + server = settings.cb_site_mail_server, + username = settings.cb_site_mail_username, + password = settings.cb_site_mail_password, + port = settings.cb_site_mail_smtp, + useTLS = settings.cb_site_mail_tls, + useSSL = settings.cb_site_mail_ssl + ); // generate content for email from template mail.setBody( - renderer.layout( - view = "/contentbox/email_templates/entry_new", - layout = "/contentbox/email_templates/layouts/email", - args = { gravatarEmail : currentAuthor.getEmail() } - ) - ); + renderer.layout( + view = "/contentbox/email_templates/entry_new", + layout = "/contentbox/email_templates/layouts/email", + args = { gravatarEmail: currentAuthor.getEmail() } + ) + ); // send it out variables.mailService.send( mail ); @@ -219,9 +224,9 @@ component extends="coldbox.system.Interceptor" accessors="true" { * @data Intercept Data * @buffer Output buffer */ - function cbadmin_preEntryRemove( event, data, buffer ){ - var entry = arguments.data.content; - var site = entry.getSite(); + function cbadmin_preEntryRemove( event, data, buffer ) { + var entry = arguments.data.content; + var site = entry.getSite(); // Get settings var settings = variables.settingService.getAllSettings(); @@ -235,11 +240,11 @@ component extends="coldbox.system.Interceptor" accessors="true" { // get mail payload var bodyTokens = { - entryTitle : entry.getTitle(), - entryExcerpt : "", - entryURL : CBHelper.linkEntry( entry = entry, ssl = site.getIsSSL() ), - entryAuthor : currentauthor.getFullName(), - entryAuthorEmail : currentAuthor.getEmail() + entryTitle : entry.getTitle(), + entryExcerpt : "", + entryURL : CBHelper.linkEntry( entry = entry, ssl = site.getIsSSL() ), + entryAuthor : currentauthor.getFullName(), + entryAuthorEmail: currentAuthor.getEmail() }; if ( entry.hasExcerpt() ) { bodyTokens.entryExcerpt = entry.renderExcerpt(); @@ -248,27 +253,27 @@ component extends="coldbox.system.Interceptor" accessors="true" { } var mail = variables.mailservice.newMail( - to = getNotifiers( site, settings ), - from = settings.cb_site_outgoingEmail, - subject = "#site.getName()# - Entry Removed - #bodyTokens.entryTitle#", - bodyTokens = bodyTokens, - type = "html", - server = settings.cb_site_mail_server, - username = settings.cb_site_mail_username, - password = settings.cb_site_mail_password, - port = settings.cb_site_mail_smtp, - useTLS = settings.cb_site_mail_tls, - useSSL = settings.cb_site_mail_ssl - ); + to = getNotifiers( site, settings ), + from = settings.cb_site_outgoingEmail, + subject = "#site.getName()# - Entry Removed - #bodyTokens.entryTitle#", + bodyTokens = bodyTokens, + type = "html", + server = settings.cb_site_mail_server, + username = settings.cb_site_mail_username, + password = settings.cb_site_mail_password, + port = settings.cb_site_mail_smtp, + useTLS = settings.cb_site_mail_tls, + useSSL = settings.cb_site_mail_ssl + ); // generate content for email from template mail.setBody( - renderer.layout( - view = "/contentbox/email_templates/entry_remove", - layout = "/contentbox/email_templates/layouts/email", - args = { gravatarEmail : currentAuthor.getEmail() } - ) - ); + renderer.layout( + view = "/contentbox/email_templates/entry_remove", + layout = "/contentbox/email_templates/layouts/email", + args = { gravatarEmail: currentAuthor.getEmail() } + ) + ); // send it out variables.mailService.send( mail ); } @@ -280,14 +285,14 @@ component extends="coldbox.system.Interceptor" accessors="true" { * @data Intercept Data * @buffer Output buffer */ - function cbadmin_postPageSave( event, data, buffer ){ + function cbadmin_postPageSave( event, data, buffer ) { // Only new pages are announced, not updates, and also verify page notifications are online. - if ( NOT arguments.data.isNew ) { + if ( !arguments.data.isNew ) { return; } - var page = arguments.data.content; - var site = page.getSite(); + var page = arguments.data.content; + var site = page.getSite(); var settings = variables.settingService.getAllSettings(); // Only notify when enabled. @@ -300,13 +305,13 @@ component extends="coldbox.system.Interceptor" accessors="true" { // get mail payload var bodyTokens = { - pageTitle : page.getTitle(), - pageURL : CBHelper.linkPage( page = page, ssl = site.getIsSSL() ), - pageAuthor : currentauthor.getFullName(), - pageAuthorEmail : currentAuthor.getEmail(), - pageIsPublished : page.getIsPublished(), - pagePublishedDate : page.getDisplayPublishedDate(), - pageExpireDate : page.getDisplayExpireDate() + pageTitle : page.getTitle(), + pageURL : CBHelper.linkPage( page = page, ssl = site.getIsSSL() ), + pageAuthor : currentauthor.getFullName(), + pageAuthorEmail : currentAuthor.getEmail(), + pageIsPublished : page.getIsPublished(), + pagePublishedDate: page.getDisplayPublishedDate(), + pageExpireDate : page.getDisplayExpireDate() }; if ( page.hasExcerpt() ) { @@ -316,27 +321,27 @@ component extends="coldbox.system.Interceptor" accessors="true" { } var mail = variables.mailservice.newMail( - to = getNotifiers( site, settings ), - from = settings.cb_site_outgoingEmail, - subject = "#site.getName()# - Page Created - #bodyTokens.pageTitle#", - bodyTokens = bodyTokens, - type = "html", - server = settings.cb_site_mail_server, - username = settings.cb_site_mail_username, - password = settings.cb_site_mail_password, - port = settings.cb_site_mail_smtp, - useTLS = settings.cb_site_mail_tls, - useSSL = settings.cb_site_mail_ssl - ); + to = getNotifiers( site, settings ), + from = settings.cb_site_outgoingEmail, + subject = "#site.getName()# - Page Created - #bodyTokens.pageTitle#", + bodyTokens = bodyTokens, + type = "html", + server = settings.cb_site_mail_server, + username = settings.cb_site_mail_username, + password = settings.cb_site_mail_password, + port = settings.cb_site_mail_smtp, + useTLS = settings.cb_site_mail_tls, + useSSL = settings.cb_site_mail_ssl + ); // generate content for email from template mail.setBody( - renderer.layout( - view = "/contentbox/email_templates/page_new", - layout = "/contentbox/email_templates/layouts/email", - args = { gravatarEmail : currentAuthor.getEmail() } - ) - ); + renderer.layout( + view = "/contentbox/email_templates/page_new", + layout = "/contentbox/email_templates/layouts/email", + args = { gravatarEmail: currentAuthor.getEmail() } + ) + ); // send it out variables.mailService.send( mail ); @@ -349,9 +354,9 @@ component extends="coldbox.system.Interceptor" accessors="true" { * @data Intercept Data * @buffer Output buffer */ - function cbadmin_prePageRemove( event, data, buffer ){ - var page = arguments.data.content; - var site = page.getSite(); + function cbadmin_prePageRemove( event, data, buffer ) { + var page = arguments.data.content; + var site = page.getSite(); // Get settings var settings = variables.settingService.getAllSettings(); @@ -365,11 +370,11 @@ component extends="coldbox.system.Interceptor" accessors="true" { // get mail payload var bodyTokens = { - pageTitle : page.getTitle(), - pageExcerpt : "", - pageURL : CBHelper.linkPage( page = page, ssl = site.getIsSSL() ), - pageAuthor : currentauthor.getFullName(), - pageAuthorEmail : currentAuthor.getEmail() + pageTitle : page.getTitle(), + pageExcerpt : "", + pageURL : CBHelper.linkPage( page = page, ssl = site.getIsSSL() ), + pageAuthor : currentauthor.getFullName(), + pageAuthorEmail: currentAuthor.getEmail() }; if ( page.hasExcerpt() ) { bodyTokens.pageExcerpt = page.renderExcerpt(); @@ -378,27 +383,27 @@ component extends="coldbox.system.Interceptor" accessors="true" { } var mail = variables.mailservice.newMail( - to = getNotifiers( site, settings ), - from = settings.cb_site_outgoingEmail, - subject = "#site.getName()# - Page Removed - #bodyTokens.pageTitle#", - bodyTokens = bodyTokens, - type = "html", - server = settings.cb_site_mail_server, - username = settings.cb_site_mail_username, - password = settings.cb_site_mail_password, - port = settings.cb_site_mail_smtp, - useTLS = settings.cb_site_mail_tls, - useSSL = settings.cb_site_mail_ssl - ); + to = getNotifiers( site, settings ), + from = settings.cb_site_outgoingEmail, + subject = "#site.getName()# - Page Removed - #bodyTokens.pageTitle#", + bodyTokens = bodyTokens, + type = "html", + server = settings.cb_site_mail_server, + username = settings.cb_site_mail_username, + password = settings.cb_site_mail_password, + port = settings.cb_site_mail_smtp, + useTLS = settings.cb_site_mail_tls, + useSSL = settings.cb_site_mail_ssl + ); // generate content for email from template mail.setBody( - renderer.layout( - view = "/contentbox/email_templates/page_remove", - layout = "/contentbox/email_templates/layouts/email", - args = { gravatarEmail : currentAuthor.getEmail() } - ) - ); + renderer.layout( + view = "/contentbox/email_templates/page_remove", + layout = "/contentbox/email_templates/layouts/email", + args = { gravatarEmail: currentAuthor.getEmail() } + ) + ); // send it out variables.mailService.send( mail ); @@ -411,14 +416,14 @@ component extends="coldbox.system.Interceptor" accessors="true" { * @data Intercept Data * @buffer Output buffer */ - function cbadmin_postContentStoreSave( event, data, buffer ){ + function cbadmin_postContentStoreSave( event, data, buffer ) { // Only new pages are announced, not updates - if ( NOT arguments.data.isNew ) { + if ( !arguments.data.isNew ) { return; } - var content = arguments.data.content; - var site = content.getSite(); + var content = arguments.data.content; + var site = content.getSite(); var settings = variables.settingService.getAllSettings(); // Only notify when enabled. @@ -431,42 +436,42 @@ component extends="coldbox.system.Interceptor" accessors="true" { // get mail payload var bodyTokens = { - contentTitle : content.getTitle(), - contentDescription : content.getDescription(), - contentAuthor : currentauthor.getFullName(), - contentAuthorEmail : currentAuthor.getEmail(), - contentIsPublished : content.getIsPublished(), - contentPublishedDate : content.getDisplayPublishedDate(), - contentExpireDate : content.getDisplayExpireDate(), - contentURL : arguments.event.buildLink( - to = "#CBHelper.adminRoot()#.contentStore.export/contentID/#content.getContentID()#", - ssl = settings.cb_admin_ssl - ), - contentExcerpt : content.renderContentSilent( content.getActiveContent().getContent() ) + contentTitle : content.getTitle(), + contentDescription : content.getDescription(), + contentAuthor : currentauthor.getFullName(), + contentAuthorEmail : currentAuthor.getEmail(), + contentIsPublished : content.getIsPublished(), + contentPublishedDate: content.getDisplayPublishedDate(), + contentExpireDate : content.getDisplayExpireDate(), + contentURL : arguments.event.buildLink( + to = "#CBHelper.adminRoot()#.contentStore.export/contentID/#content.getContentID()#", + ssl = settings.cb_admin_ssl + ), + contentExcerpt: content.renderContentSilent( content.getActiveContent().getContent() ) }; var mail = variables.mailservice.newMail( - to = getNotifiers( site, settings ), - from = settings.cb_site_outgoingEmail, - subject = "#site.getName()# - ContentStore Created - #bodyTokens.contentTitle#", - bodyTokens = bodyTokens, - type = "html", - server = settings.cb_site_mail_server, - username = settings.cb_site_mail_username, - password = settings.cb_site_mail_password, - port = settings.cb_site_mail_smtp, - useTLS = settings.cb_site_mail_tls, - useSSL = settings.cb_site_mail_ssl - ); + to = getNotifiers( site, settings ), + from = settings.cb_site_outgoingEmail, + subject = "#site.getName()# - ContentStore Created - #bodyTokens.contentTitle#", + bodyTokens = bodyTokens, + type = "html", + server = settings.cb_site_mail_server, + username = settings.cb_site_mail_username, + password = settings.cb_site_mail_password, + port = settings.cb_site_mail_smtp, + useTLS = settings.cb_site_mail_tls, + useSSL = settings.cb_site_mail_ssl + ); // generate content for email from template mail.setBody( - renderer.layout( - view = "/contentbox/email_templates/contentstore_new", - layout = "/contentbox/email_templates/layouts/email", - args = { gravatarEmail : currentAuthor.getEmail() } - ) - ); + renderer.layout( + view = "/contentbox/email_templates/contentstore_new", + layout = "/contentbox/email_templates/layouts/email", + args = { gravatarEmail: currentAuthor.getEmail() } + ) + ); // send it out variables.mailService.send( mail ); @@ -479,9 +484,9 @@ component extends="coldbox.system.Interceptor" accessors="true" { * @data Intercept Data * @buffer Output buffer */ - function cbadmin_preContentStoreRemove( event, data, buffer ){ - var content = arguments.data.content; - var site = content.getSite(); + function cbadmin_preContentStoreRemove( event, data, buffer ) { + var content = arguments.data.content; + var site = content.getSite(); // Get settings var settings = variables.settingService.getAllSettings(); @@ -495,42 +500,42 @@ component extends="coldbox.system.Interceptor" accessors="true" { // get mail payload var bodyTokens = { - contentTitle : content.getTitle(), - contentDescription : content.getDescription(), - contentAuthor : currentauthor.getFullName(), - contentAuthorEmail : currentAuthor.getEmail(), - contentIsPublished : content.getIsPublished(), - contentPublishedDate : content.getDisplayPublishedDate(), - contentExpireDate : content.getDisplayExpireDate(), - contentURL : arguments.event.buildLink( - to = "#CBHelper.adminRoot()#.contentStore.export/contentID/#content.getContentID()#", - ssl = settings.cb_admin_ssl - ), - contentExcerpt : content.renderContentSilent( content.getActiveContent().getContent() ) + contentTitle : content.getTitle(), + contentDescription : content.getDescription(), + contentAuthor : currentauthor.getFullName(), + contentAuthorEmail : currentAuthor.getEmail(), + contentIsPublished : content.getIsPublished(), + contentPublishedDate: content.getDisplayPublishedDate(), + contentExpireDate : content.getDisplayExpireDate(), + contentURL : arguments.event.buildLink( + to = "#CBHelper.adminRoot()#.contentStore.export/contentID/#content.getContentID()#", + ssl = settings.cb_admin_ssl + ), + contentExcerpt: content.renderContentSilent( content.getActiveContent().getContent() ) }; var mail = variables.mailservice.newMail( - to = getNotifiers( site, settings ), - from = settings.cb_site_outgoingEmail, - subject = "#site.getName()# - ContentStore Removed - #bodyTokens.contentTitle#", - bodyTokens = bodyTokens, - type = "html", - server = settings.cb_site_mail_server, - username = settings.cb_site_mail_username, - password = settings.cb_site_mail_password, - port = settings.cb_site_mail_smtp, - useTLS = settings.cb_site_mail_tls, - useSSL = settings.cb_site_mail_ssl - ); + to = getNotifiers( site, settings ), + from = settings.cb_site_outgoingEmail, + subject = "#site.getName()# - ContentStore Removed - #bodyTokens.contentTitle#", + bodyTokens = bodyTokens, + type = "html", + server = settings.cb_site_mail_server, + username = settings.cb_site_mail_username, + password = settings.cb_site_mail_password, + port = settings.cb_site_mail_smtp, + useTLS = settings.cb_site_mail_tls, + useSSL = settings.cb_site_mail_ssl + ); // generate content for email from template mail.setBody( - renderer.layout( - view = "/contentbox/email_templates/contentstore_remove", - layout = "/contentbox/email_templates/layouts/email", - args = { gravatarEmail : currentAuthor.getEmail() } - ) - ); + renderer.layout( + view = "/contentbox/email_templates/contentstore_remove", + layout = "/contentbox/email_templates/layouts/email", + args = { gravatarEmail: currentAuthor.getEmail() } + ) + ); // send it out variables.mailService.send( mail ); @@ -542,7 +547,7 @@ component extends="coldbox.system.Interceptor" accessors="true" { * @site The site the notification is from * @settings The global settings */ - private function getNotifiers( required site, required settings ){ + private function getNotifiers( required site, required settings ) { var notifiers = ""; // Site Notifiers if ( arguments.site.getNotifyOnEntries() ) { @@ -555,4 +560,4 @@ component extends="coldbox.system.Interceptor" accessors="true" { return notifiers; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/system/Setting.cfc b/modules/contentbox/models/system/Setting.cfc index 8a18a948e3..eb8af843e0 100755 --- a/modules/contentbox/models/system/Setting.cfc +++ b/modules/contentbox/models/system/Setting.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -15,77 +15,67 @@ component cachename ="cbSetting" cacheuse ="read-write" { - - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ property - name ="settingID" - column ="settingID" + name="settingID" + column="settingID" fieldtype="id" generator="uuid" - length ="36" - ormtype ="string" - update ="false"; + length="36" + ormtype="string" + update="false"; - property - name ="name" - column ="name" - notnull="true" - length ="100"; + property name="name" column="name" notnull="true" length="100"; - property - name ="value" - column ="value" - notnull="true" - ormtype="text"; + property name="value" column="value" notnull="true" ormtype="text"; property - name ="isCore" - column ="isCore" + name="isCore" + column="isCore" ormtype="boolean" notnull="true" default="false" - index ="idx_core"; + index="idx_core"; - /* ********************************************************************* - ** RELATIONSHIPS - ********************************************************************* */ + /********************************************************************** + * ** RELATIONSHIPS + **********************************************************************/ // M20 -> The site this setting belongs to property - name ="site" - notnull ="false" - cfc ="contentbox.models.system.Site" + name="site" + notnull="false" + cfc="contentbox.models.system.Site" fieldtype="many-to-one" - fkcolumn ="FK_siteID" - lazy ="true"; - - /* ********************************************************************* - ** PK + CONSTRAINTS + Memento - ********************************************************************* */ + fkcolumn="FK_siteID" + lazy="true"; + /********************************************************************** + * ** PK + CONSTRAINTS + Memento + **********************************************************************/ this.pk = "settingID"; this.constraints = { - "name" : { required : true, size : "1..100" }, - "value" : { required : true } + "name" : { required: true, size: "1..100" }, + "value": { required: true } }; this.memento = { - defaultIncludes : [ "name", "value", "isCore", "siteSnapshot:site" ], - defaultExcludes : [ "site" ] + defaultIncludes: [ "name", "value", "isCore", "siteSnapshot:site"], + defaultExcludes: [ "site"] }; - /* ********************************************************************* - ** PUBLIC METHODS - ********************************************************************* */ + /********************************************************************** + * ** PUBLIC METHODS + **********************************************************************/ /** * Constructor */ - function init(){ + function init() { variables.isCore = false; super.init(); @@ -96,7 +86,7 @@ component /** * Build a site snapshot */ - struct function getSiteSnapshot(){ + struct function getSiteSnapshot() { return ( hasSite() ? getSite().getInfoSnapshot() : {} ); } @@ -105,11 +95,11 @@ component * * @return The associated site id or empty if none */ - function getSiteID(){ + function getSiteID() { if ( hasSite() ) { return getSite().getsiteID(); } return ""; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/system/SettingService.cfc b/modules/contentbox/models/system/SettingService.cfc index 00760f57b6..925468e1c2 100755 --- a/modules/contentbox/models/system/SettingService.cfc +++ b/modules/contentbox/models/system/SettingService.cfc @@ -7,22 +7,21 @@ * All settings are cached as a struct constructed using the following format: * - global : { name : value } // global settings * - sites : { - * slug : { name : value } + * slug : { name : value } * } */ -component - extends ="cborm.models.VirtualEntityService" - accessors="true" - threadsafe - singleton -{ - +component extends ="cborm.models.VirtualEntityService" accessors="true" threadsafe singleton { // DI properties property name="siteService" inject="siteService@contentbox"; + property name="cachebox" inject="cachebox"; + property name="moduleSettings" inject="coldbox:setting:modules"; + property name="appName" inject="coldbox:setting:appName"; + property name="contentboxSettings" inject="coldbox:moduleSettings:contentbox"; + property name="log" inject="logbox:logger:{this}"; /** @@ -34,123 +33,119 @@ component /** * Bit that detects if CB has been installed or not */ - property - name ="CBReadyFlag" - default="false" - type ="boolean"; - + property name="CBReadyFlag" default="false" type="boolean"; // Global Setting Defaults this.DEFAULTS = { // ContentBox Global Version - "cb_version" : "@version.number@+@build.number@", + "cb_version" : "@version.number@+@build.number@", // Installation security salt - "cb_salt" : hash( createUUID() & getTickCount() & now(), "SHA-512" ), + "cb_salt" : hash( createUUID() & getTickCount() & now(), "SHA-512" ), // Global Notifications - "cb_site_email" : "", - "cb_notify_author" : "true", - "cb_notify_entry" : "true", - "cb_notify_page" : "true", - "cb_notify_contentstore" : "true", + "cb_site_email" : "", + "cb_notify_author" : "true", + "cb_notify_entry" : "true", + "cb_notify_page" : "true", + "cb_notify_contentstore" : "true", // Outgoing email - "cb_site_outgoingEmail" : "", + "cb_site_outgoingEmail" : "", // Blog Entry Point - "cb_site_blog_entrypoint" : "blog", + "cb_site_blog_entrypoint" : "blog", // Caching - "cb_site_settings_cache" : "template", + "cb_site_settings_cache" : "template", // Security Settings - "cb_security_min_password_length" : "8", - "cb_security_password_reset_expiration" : "60", - "cb_security_login_blocker" : "true", - "cb_security_max_attempts" : "5", - "cb_security_blocktime" : "5", - "cb_security_max_auth_logs" : "500", - "cb_security_latest_logins" : "10", - "cb_security_rate_limiter" : "true", - "cb_security_rate_limiter_logging" : "true", - "cb_security_rate_limiter_count" : "4", - "cb_security_rate_limiter_duration" : "1", - "cb_security_rate_limiter_bots_only" : "true", - "cb_security_rate_limiter_message" : "

      You are making too many requests too fast, please slow down and wait {duration} seconds

      ", - "cb_security_rate_limiter_redirectURL" : "", - "cb_security_2factorAuth_force" : "false", - "cb_security_2factorAuth_provider" : "email", - "cb_security_2factorAuth_trusted_days" : "30", - "cb_security_login_signout_url" : "", - "cb_security_login_signin_text" : "", + "cb_security_min_password_length" : "8", + "cb_security_password_reset_expiration": "60", + "cb_security_login_blocker" : "true", + "cb_security_max_attempts" : "5", + "cb_security_blocktime" : "5", + "cb_security_max_auth_logs" : "500", + "cb_security_latest_logins" : "10", + "cb_security_rate_limiter" : "true", + "cb_security_rate_limiter_logging" : "true", + "cb_security_rate_limiter_count" : "4", + "cb_security_rate_limiter_duration" : "1", + "cb_security_rate_limiter_bots_only" : "true", + "cb_security_rate_limiter_message" : "

      You are making too many requests too fast, please slow down and wait {duration} seconds

      ", + "cb_security_rate_limiter_redirectURL" : "", + "cb_security_2factorAuth_force" : "false", + "cb_security_2factorAuth_provider" : "email", + "cb_security_2factorAuth_trusted_days" : "30", + "cb_security_login_signout_url" : "", + "cb_security_login_signin_text" : "", // Admin settings - "cb_admin_ssl" : "false", - "cb_admin_quicksearch_max" : "5", - "cb_admin_theme" : "contentbox-default", + "cb_admin_ssl" : "false", + "cb_admin_quicksearch_max" : "5", + "cb_admin_theme" : "contentbox-default", // Paging Defaults - "cb_paging_maxrows" : "20", - "cb_paging_bandgap" : "5", - "cb_paging_maxentries" : "10", - "cb_paging_maxRSSComments" : "10", + "cb_paging_maxrows" : "20", + "cb_paging_bandgap" : "5", + "cb_paging_maxentries" : "10", + "cb_paging_maxRSSComments" : "10", // Gravatar - "cb_gravatar_display" : "true", - "cb_gravatar_rating" : "PG", + "cb_gravatar_display" : "true", + "cb_gravatar_rating" : "PG", // Dashboard Settings - "cb_dashboard_recentEntries" : "5", - "cb_dashboard_recentPages" : "5", - "cb_dashboard_recentComments" : "5", - "cb_dashboard_recentcontentstore" : "5", - "cb_dashboard_newsfeed" : "https://www.ortussolutions.com/blog/rss", - "cb_dashboard_newsfeed_count" : "5", - "cb_dashboard_welcome_title" : "Dashboard", - "cb_dashboard_welcome_body" : "", + "cb_dashboard_recentEntries" : "5", + "cb_dashboard_recentPages" : "5", + "cb_dashboard_recentComments" : "5", + "cb_dashboard_recentcontentstore" : "5", + "cb_dashboard_newsfeed" : "https://www.ortussolutions.com/blog/rss", + "cb_dashboard_newsfeed_count" : "5", + "cb_dashboard_welcome_title" : "Dashboard", + "cb_dashboard_welcome_body" : "", // Global Comment Settings - "cb_comments_whoisURL" : "http://whois.arin.net/ui/query.do?q", + "cb_comments_whoisURL" : "http://whois.arin.net/ui/query.do?q", // Mail Settings - "cb_site_mail_server" : "", - "cb_site_mail_username" : "", - "cb_site_mail_password" : "", - "cb_site_mail_smtp" : "25", - "cb_site_mail_tls" : "false", - "cb_site_mail_ssl" : "false", + "cb_site_mail_server" : "", + "cb_site_mail_username" : "", + "cb_site_mail_password" : "", + "cb_site_mail_smtp" : "25", + "cb_site_mail_tls" : "false", + "cb_site_mail_ssl" : "false", // RSS Feeds - "cb_rss_maxEntries" : "10", - "cb_rss_maxComments" : "10", - "cb_rss_caching" : "true", - "cb_rss_cachingTimeout" : "60", - "cb_rss_cachingTimeoutIdle" : "15", - "cb_rss_cacheName" : "Template", - "cb_rss_title" : "RSS Feed by ContentBox", - "cb_rss_generator" : "ContentBox by Ortus Solutions", - "cb_rss_copyright" : "Ortus Solutions, Corp (www.ortussolutions.com)", - "cb_rss_description" : "ContentBox RSS Feed", - "cb_rss_webmaster" : "", + "cb_rss_maxEntries" : "10", + "cb_rss_maxComments" : "10", + "cb_rss_caching" : "true", + "cb_rss_cachingTimeout" : "60", + "cb_rss_cachingTimeoutIdle" : "15", + "cb_rss_cacheName" : "Template", + "cb_rss_title" : "RSS Feed by ContentBox", + "cb_rss_generator" : "ContentBox by Ortus Solutions", + "cb_rss_copyright" : "Ortus Solutions, Corp (www.ortussolutions.com)", + "cb_rss_description" : "ContentBox RSS Feed", + "cb_rss_webmaster" : "", // Content Caching and options - "cb_content_caching" : "true", - "cb_entry_caching" : "true", - "cb_contentstore_caching" : "true", - "cb_content_cachingTimeout" : "60", - "cb_content_cachingTimeoutIdle" : "15", - "cb_content_cacheName" : "Template", - "cb_page_excerpts" : "true", - "cb_content_uiexport" : "true", - "cb_content_cachingHeader" : "true", + "cb_content_caching" : "true", + "cb_entry_caching" : "true", + "cb_contentstore_caching" : "true", + "cb_content_cachingTimeout" : "60", + "cb_content_cachingTimeoutIdle" : "15", + "cb_content_cacheName" : "Template", + "cb_page_excerpts" : "true", + "cb_content_uiexport" : "true", + "cb_content_cachingHeader" : "true", // Content Hit Tracking - "cb_content_hit_count" : "true", - "cb_content_hit_ignore_bots" : "false", - "cb_content_bot_regex" : "Googlebot(?:[\/-](\w+))?|AdsBot-Google(?:-(\w+)|[^-]?) |Feedfetcher-Google|Mediapartners-Google|Mediapartners \(Googlebot\)|APIs-Google|Google-InspectionTool|Storebot-Google|GoogleOther|bingbot|Slurp|[wW]get|LinkedInBot|Python-urllib|python-requests|aiohttp|httpx|libwww-perl|httpunit|Nutch|Go-http-client|phpcrawl|msnbot|jyxobot|FAST-WebCrawler|FAST Enterprise Crawler|BIGLOTRON|Teoma|convera|seekbot|Gigabot|Gigablast|exabot|ia_archiver|GingerCrawler|webmon |HTTrack|grub\.org|UsineNouvelleCrawler|antibot|netresearchserver|speedy|fluffy|findlink|msrbot|panscient|yacybot|AISearchBot|ips-agent|tagoobot|MJ12bot|woriobot|yanga|buzzbot|mlbot|yandex\.com\/bots|purebot|Linguee Bot|CyberPatrol|voilabot|Baiduspider|citeseerxbot|spbot|twengabot|postrank|Turnitin|scribdbot|page2rss|sitebot|linkdex|Adidxbot|ezooms|dotbot|Mail\.RU_Bot|discobot|heritrix|findthatfile|europarchive\.org|NerdByNature\.Bot|(sistrix|SISTRIX) [cC]rawler|Ahrefs(Bot|SiteAudit)|fuelbot|CrunchBot|IndeedBot|mappydata|woobot|ZoominfoBot|PrivacyAwareBot|Multiviewbot|SWIMGBot|Grobbot|eright|Apercite|semanticbot|Aboundex|domaincrawler|wbsearchbot|summify|CCBot|edisterbot|SeznamBot|ec2linkfinder|gslfbot|aiHitBot|intelium_bot|facebookexternalhit|Yeti|RetrevoPageAnalyzer|lb-spider|Sogou|lssbot|careerbot|wotbox|wocbot|ichiro|DuckDuckBot|lssrocketcrawler|drupact|webcompanycrawler|acoonbot|openindexspider|gnam gnam spider|web-archive-net\.com\.bot|backlinkcrawler|coccoc|integromedb|content crawler spider|toplistbot|it2media-domain-crawler|ip-web-crawler\.com|siteexplorer\.info|elisabot|proximic|changedetection|arabot|WeSEE:Search|niki-bot|CrystalSemanticsBot|rogerbot|360Spider|psbot|InterfaxScanBot|CC Metadata Scaper|g00g1e\.net|GrapeshotCrawler|urlappendbot|brainobot|fr-crawler|binlar|SimpleCrawler|Twitterbot|cXensebot|smtbot|bnf\.fr_bot|A6-Indexer|ADmantX|Facebot|OrangeBot\/|memorybot|AdvBot|MegaIndex|SemanticScholarBot|ltx71|nerdybot|xovibot|BUbiNG|Qwantify|archive\.org_bot|Applebot|TweetmemeBot|crawler4j|findxbot|S[eE][mM]rushBot|yoozBot|lipperhey|Y!J|Domain Re-Animator Bot|AddThis|Screaming Frog SEO Spider|MetaURI|Scrapy|Livelap[bB]ot|OpenHoseBot|CapsuleChecker|collection@infegy\.com|IstellaBot|DeuSu\/|betaBot|Cliqzbot\/|MojeekBot\/|netEstate NE Crawler|SafeSearch microdata crawler|Gluten Free Crawler\/|Sonic|Sysomos|Trove|deadlinkchecker|Slack-ImgProxy|Embedly|RankActiveLinkBot|iskanie|SafeDNSBot|SkypeUriPreview|Veoozbot|Slackbot|redditbot|datagnionbot|Google-Adwords-Instant|adbeat_bot|WhatsApp|contxbot|pinterest\.com\/bot|electricmonk|GarlikCrawler|BingPreview\/|vebidoobot|FemtosearchBot|Yahoo Link Preview|MetaJobBot|DomainStatsBot|mindUpBot|Daum\/|Jugendschutzprogramm-Crawler|Xenu Link Sleuth|Pcore-HTTP|moatbot|KosmioBot|[pP]ingdom|AppInsights|PhantomJS|Gowikibot|PiplBot|Discordbot|TelegramBot|Jetslide|newsharecounts|James BOT|Bark[rR]owler|TinEye|SocialRankIOBot|trendictionbot|Ocarinabot|epicbot|Primalbot|DuckDuckGo-Favicons-Bot|GnowitNewsbot|Leikibot|LinkArchiver|YaK\/|PaperLiBot|Digg Deeper|dcrawl|Snacktory|AndersPinkBot|Fyrebot|EveryoneSocialBot|Mediatoolkitbot|Luminator-robots|ExtLinksBot|SurveyBot|NING\/|okhttp|Nuzzel|omgili|PocketParser|YisouSpider|um-LN|ToutiaoSpider|MuckRack|Jamie's Spider|AHC\/|NetcraftSurveyAgent|Laserlikebot|^Apache-HttpClient|AppEngine-Google|Jetty|Upflow|Thinklab|Traackr\.com|Twurly|Mastodon|http_get|DnyzBot|botify|007ac9 Crawler|BehloolBot|BrandVerity|check_http|BDCbot|ZumBot|EZID|ICC-Crawler|ArchiveBot|^LCC |filterdb\.iss\.net\/crawler|BLP_bbot|BomboraBot|Buck\/|Companybook-Crawler|Genieo|magpie-crawler|MeltwaterNews|Moreover|newspaper\/|ScoutJet|(^| )sentry\/|StorygizeBot|UptimeRobot|OutclicksBot|seoscanners|Hatena|Google Web Preview|MauiBot|AlphaBot|SBL-BOT|IAS crawler|adscanner|Netvibes|acapbot|Baidu-YunGuanCe|bitlybot|blogmuraBot|Bot\.AraTurka\.com|bot-pge\.chlooe\.com|BoxcarBot|BTWebClient|ContextAd Bot|Digincore bot|Disqus|Feedly|Fetch\/|Fever|Flamingo_SearchEngine|FlipboardProxy|g2reader-bot|G2 Web Services|imrbot|K7MLWCBot|Kemvibot|Landau-Media-Spider|linkapediabot|vkShare|Siteimprove\.com|BLEXBot\/|DareBoost|ZuperlistBot\/|Miniflux\/|Feedspot|Diffbot\/|SEOkicks|tracemyfile|Nimbostratus-Bot|zgrab|PR-CY\.RU|AdsTxtCrawler|Datafeedwatch|Zabbix|TangibleeBot|google-xrawler|axios|Amazon CloudFront|Pulsepoint|CloudFlare-AlwaysOnline|Cloudflare-Healthchecks|Cloudflare-Traffic-Manager|CloudFlare-Prefetch|Cloudflare-SSLDetector|https:\/\/developers\.cloudflare\.com\/security-center\/|Google-Structured-Data-Testing-Tool|WordupInfoSearch|WebDataStats|HttpUrlConnection|ZoomBot|VelenPublicWebCrawler|MoodleBot|jpg-newsbot|outbrain|W3C_Validator|Validator\.nu|W3C-checklink|W3C-mobileOK|W3C_I18n-Checker|FeedValidator|W3C_CSS_Validator|W3C_Unicorn|Google-PhysicalWeb|Blackboard|ICBot\/|BazQux|Twingly|Rivva|Experibot|awesomecrawler|Dataprovider\.com|GroupHigh\/|theoldreader\.com|AnyEvent|Uptimebot\.org|Nmap Scripting Engine|2ip\.ru|Clickagy|Caliperbot|MBCrawler|online-webceo-bot|B2B Bot|AddSearchBot|Google Favicon|HubSpot|Chrome-Lighthouse|HeadlessChrome|CheckMarkNetwork\/|www\.uptime\.com|Streamline3Bot\/|serpstatbot\/|MixnodeCache\/|^curl|SimpleScraper|RSSingBot|Jooblebot|fedoraplanet|Friendica|NextCloud|Tiny Tiny RSS|RegionStuttgartBot|Bytespider|Datanyze|Google-Site-Verification|TrendsmapResolver|tweetedtimes|NTENTbot|Gwene|SimplePie|SearchAtlas|Superfeedr|feedbot|UT-Dorkbot|Amazonbot|SerendeputyBot|Eyeotabot|officestorebot|Neticle Crawler|SurdotlyBot|LinkisBot|AwarioSmartBot|AwarioRssBot|RyteBot|FreeWebMonitoring SiteChecker|AspiegelBot|NAVER Blog Rssbot|zenback bot|SentiBot|Domains Project\/|Pandalytics|VKRobot|bidswitchbot|tigerbot|NIXStatsbot|Atom Feed Robot|[Cc]urebot|PagePeeker\/|Vigil\/|rssbot\/|startmebot\/|JobboerseBot|seewithkids|NINJA bot|Cutbot|BublupBot|BrandONbot|RidderBot|Taboolabot|Dubbotbot|FindITAnswersbot|infoobot|Refindbot|BlogTraffic\/\d\.\d+ Feed-Fetcher|SeobilityBot|Cincraw|Dragonbot|VoluumDSP-content-bot|FreshRSS|BitBot|^PHP-Curl-Class|Google-Certificates-Bridge|centurybot|Viber|e\.ventures Investment Crawler|evc-batch|PetalBot|virustotal|(^| )PTST\/|minicrawler|Cookiebot|trovitBot|seostar\.co|IonCrawl|Uptime-Kuma|Seekport|FreshpingBot|Feedbin|CriteoBot|Snap URL Preview Service|Better Uptime Bot|RuxitSynthetic|Google-Read-Aloud|Valve\/Steam|OdklBot\/|GPTBot|ChatGPT-User|OAI-SearchBot|YandexRenderResourcesBot\/|LightspeedSystemsCrawler|ev-crawler\/|BitSightBot\/|woorankreview\/|Google-Safety|AwarioBot|DataForSeoBot|Linespider|WellKnownBot|A Patent Crawler|StractBot|search\.marginalia\.nu|YouBot|Nicecrawler|Neevabot|BrightEdge Crawler|SiteCheckerBotCrawler|TombaPublicWebCrawler|CrawlyProjectCrawler|KomodiaBot|KStandBot|CISPA Webcrawler|MTRobot|hyscore\.io|AlexandriaOrgBot|2ip bot|Yellowbrandprotectionbot|SEOlizer|vuhuvBot|INETDEX-BOT|Synapse|t3versionsBot|deepnoc|Cocolyzebot|hypestat|ReverseEngineeringBot|sempi\.tech|Iframely|MetaInspector|node-fetch|lkxscan|python-opengraph|OpenGraphCheck|developers\.google\.com\/\+\/web\/snippet|SenutoBot|MaCoCu|NewsBlur|inoreader|NetSystemsResearch|PageThing|WordPress\/|PhxBot|ImagesiftBot|Expanse|InternetMeasurement|^BW\/|GeedoBot|Audisto Crawler|PerplexityBot\/|[cC]laude[bB]ot|Monsidobot|GroupMeBot|Vercelbot|vercel-screenshot|facebookcatalog\/|meta-externalagent\/|meta-externalfetcher\/|AcademicBotRTU|KeybaseBot|Lemmy|CookieHubScan|Hydrozen\.io|HTTP Banner Detection|SummalyBot|MicrosoftPreview\/", + "cb_content_hit_count" : "true", + "cb_content_hit_ignore_bots" : "false", + "cb_content_bot_regex" : "Googlebot(?:[\/-](\w+))?|AdsBot-Google(?:-(\w+)|[^-]?) |Feedfetcher-Google|Mediapartners-Google|Mediapartners \(Googlebot\)|APIs-Google|Google-InspectionTool|Storebot-Google|GoogleOther|bingbot|Slurp|[wW]get|LinkedInBot|Python-urllib|python-requests|aiohttp|httpx|libwww-perl|httpunit|Nutch|Go-http-client|phpcrawl|msnbot|jyxobot|FAST-WebCrawler|FAST Enterprise Crawler|BIGLOTRON|Teoma|convera|seekbot|Gigabot|Gigablast|exabot|ia_archiver|GingerCrawler|webmon |HTTrack|grub\.org|UsineNouvelleCrawler|antibot|netresearchserver|speedy|fluffy|findlink|msrbot|panscient|yacybot|AISearchBot|ips-agent|tagoobot|MJ12bot|woriobot|yanga|buzzbot|mlbot|yandex\.com\/bots|purebot|Linguee Bot|CyberPatrol|voilabot|Baiduspider|citeseerxbot|spbot|twengabot|postrank|Turnitin|scribdbot|page2rss|sitebot|linkdex|Adidxbot|ezooms|dotbot|Mail\.RU_Bot|discobot|heritrix|findthatfile|europarchive\.org|NerdByNature\.Bot|(sistrix|SISTRIX) [cC]rawler|Ahrefs(Bot|SiteAudit)|fuelbot|CrunchBot|IndeedBot|mappydata|woobot|ZoominfoBot|PrivacyAwareBot|Multiviewbot|SWIMGBot|Grobbot|eright|Apercite|semanticbot|Aboundex|domaincrawler|wbsearchbot|summify|CCBot|edisterbot|SeznamBot|ec2linkfinder|gslfbot|aiHitBot|intelium_bot|facebookexternalhit|Yeti|RetrevoPageAnalyzer|lb-spider|Sogou|lssbot|careerbot|wotbox|wocbot|ichiro|DuckDuckBot|lssrocketcrawler|drupact|webcompanycrawler|acoonbot|openindexspider|gnam gnam spider|web-archive-net\.com\.bot|backlinkcrawler|coccoc|integromedb|content crawler spider|toplistbot|it2media-domain-crawler|ip-web-crawler\.com|siteexplorer\.info|elisabot|proximic|changedetection|arabot|WeSEE:Search|niki-bot|CrystalSemanticsBot|rogerbot|360Spider|psbot|InterfaxScanBot|CC Metadata Scaper|g00g1e\.net|GrapeshotCrawler|urlappendbot|brainobot|fr-crawler|binlar|SimpleCrawler|Twitterbot|cXensebot|smtbot|bnf\.fr_bot|A6-Indexer|ADmantX|Facebot|OrangeBot\/|memorybot|AdvBot|MegaIndex|SemanticScholarBot|ltx71|nerdybot|xovibot|BUbiNG|Qwantify|archive\.org_bot|Applebot|TweetmemeBot|crawler4j|findxbot|S[eE][mM]rushBot|yoozBot|lipperhey|Y!J|Domain Re-Animator Bot|AddThis|Screaming Frog SEO Spider|MetaURI|Scrapy|Livelap[bB]ot|OpenHoseBot|CapsuleChecker|collection@infegy\.com|IstellaBot|DeuSu\/|betaBot|Cliqzbot\/|MojeekBot\/|netEstate NE Crawler|SafeSearch microdata crawler|Gluten Free Crawler\/|Sonic|Sysomos|Trove|deadlinkchecker|Slack-ImgProxy|Embedly|RankActiveLinkBot|iskanie|SafeDNSBot|SkypeUriPreview|Veoozbot|Slackbot|redditbot|datagnionbot|Google-Adwords-Instant|adbeat_bot|WhatsApp|contxbot|pinterest\.com\/bot|electricmonk|GarlikCrawler|BingPreview\/|vebidoobot|FemtosearchBot|Yahoo Link Preview|MetaJobBot|DomainStatsBot|mindUpBot|Daum\/|Jugendschutzprogramm-Crawler|Xenu Link Sleuth|Pcore-HTTP|moatbot|KosmioBot|[pP]ingdom|AppInsights|PhantomJS|Gowikibot|PiplBot|Discordbot|TelegramBot|Jetslide|newsharecounts|James BOT|Bark[rR]owler|TinEye|SocialRankIOBot|trendictionbot|Ocarinabot|epicbot|Primalbot|DuckDuckGo-Favicons-Bot|GnowitNewsbot|Leikibot|LinkArchiver|YaK\/|PaperLiBot|Digg Deeper|dcrawl|Snacktory|AndersPinkBot|Fyrebot|EveryoneSocialBot|Mediatoolkitbot|Luminator-robots|ExtLinksBot|SurveyBot|NING\/|okhttp|Nuzzel|omgili|PocketParser|YisouSpider|um-LN|ToutiaoSpider|MuckRack|Jamie's Spider|AHC\/|NetcraftSurveyAgent|Laserlikebot|^Apache-HttpClient|AppEngine-Google|Jetty|Upflow|Thinklab|Traackr\.com|Twurly|Mastodon|http_get|DnyzBot|botify|007ac9 Crawler|BehloolBot|BrandVerity|check_http|BDCbot|ZumBot|EZID|ICC-Crawler|ArchiveBot|^LCC |filterdb\.iss\.net\/crawler|BLP_bbot|BomboraBot|Buck\/|Companybook-Crawler|Genieo|magpie-crawler|MeltwaterNews|Moreover|newspaper\/|ScoutJet|(^| )sentry\/|StorygizeBot|UptimeRobot|OutclicksBot|seoscanners|Hatena|Google Web Preview|MauiBot|AlphaBot|SBL-BOT|IAS crawler|adscanner|Netvibes|acapbot|Baidu-YunGuanCe|bitlybot|blogmuraBot|Bot\.AraTurka\.com|bot-pge\.chlooe\.com|BoxcarBot|BTWebClient|ContextAd Bot|Digincore bot|Disqus|Feedly|Fetch\/|Fever|Flamingo_SearchEngine|FlipboardProxy|g2reader-bot|G2 Web Services|imrbot|K7MLWCBot|Kemvibot|Landau-Media-Spider|linkapediabot|vkShare|Siteimprove\.com|BLEXBot\/|DareBoost|ZuperlistBot\/|Miniflux\/|Feedspot|Diffbot\/|SEOkicks|tracemyfile|Nimbostratus-Bot|zgrab|PR-CY\.RU|AdsTxtCrawler|Datafeedwatch|Zabbix|TangibleeBot|google-xrawler|axios|Amazon CloudFront|Pulsepoint|CloudFlare-AlwaysOnline|Cloudflare-Healthchecks|Cloudflare-Traffic-Manager|CloudFlare-Prefetch|Cloudflare-SSLDetector|https:\/\/developers\.cloudflare\.com\/security-center\/|Google-Structured-Data-Testing-Tool|WordupInfoSearch|WebDataStats|HttpUrlConnection|ZoomBot|VelenPublicWebCrawler|MoodleBot|jpg-newsbot|outbrain|W3C_Validator|Validator\.nu|W3C-checklink|W3C-mobileOK|W3C_I18n-Checker|FeedValidator|W3C_CSS_Validator|W3C_Unicorn|Google-PhysicalWeb|Blackboard|ICBot\/|BazQux|Twingly|Rivva|Experibot|awesomecrawler|Dataprovider\.com|GroupHigh\/|theoldreader\.com|AnyEvent|Uptimebot\.org|Nmap Scripting Engine|2ip\.ru|Clickagy|Caliperbot|MBCrawler|online-webceo-bot|B2B Bot|AddSearchBot|Google Favicon|HubSpot|Chrome-Lighthouse|HeadlessChrome|CheckMarkNetwork\/|www\.uptime\.com|Streamline3Bot\/|serpstatbot\/|MixnodeCache\/|^curl|SimpleScraper|RSSingBot|Jooblebot|fedoraplanet|Friendica|NextCloud|Tiny Tiny RSS|RegionStuttgartBot|Bytespider|Datanyze|Google-Site-Verification|TrendsmapResolver|tweetedtimes|NTENTbot|Gwene|SimplePie|SearchAtlas|Superfeedr|feedbot|UT-Dorkbot|Amazonbot|SerendeputyBot|Eyeotabot|officestorebot|Neticle Crawler|SurdotlyBot|LinkisBot|AwarioSmartBot|AwarioRssBot|RyteBot|FreeWebMonitoring SiteChecker|AspiegelBot|NAVER Blog Rssbot|zenback bot|SentiBot|Domains Project\/|Pandalytics|VKRobot|bidswitchbot|tigerbot|NIXStatsbot|Atom Feed Robot|[Cc]urebot|PagePeeker\/|Vigil\/|rssbot\/|startmebot\/|JobboerseBot|seewithkids|NINJA bot|Cutbot|BublupBot|BrandONbot|RidderBot|Taboolabot|Dubbotbot|FindITAnswersbot|infoobot|Refindbot|BlogTraffic\/\d\.\d+ Feed-Fetcher|SeobilityBot|Cincraw|Dragonbot|VoluumDSP-content-bot|FreshRSS|BitBot|^PHP-Curl-Class|Google-Certificates-Bridge|centurybot|Viber|e\.ventures Investment Crawler|evc-batch|PetalBot|virustotal|(^| )PTST\/|minicrawler|Cookiebot|trovitBot|seostar\.co|IonCrawl|Uptime-Kuma|Seekport|FreshpingBot|Feedbin|CriteoBot|Snap URL Preview Service|Better Uptime Bot|RuxitSynthetic|Google-Read-Aloud|Valve\/Steam|OdklBot\/|GPTBot|ChatGPT-User|OAI-SearchBot|YandexRenderResourcesBot\/|LightspeedSystemsCrawler|ev-crawler\/|BitSightBot\/|woorankreview\/|Google-Safety|AwarioBot|DataForSeoBot|Linespider|WellKnownBot|A Patent Crawler|StractBot|search\.marginalia\.nu|YouBot|Nicecrawler|Neevabot|BrightEdge Crawler|SiteCheckerBotCrawler|TombaPublicWebCrawler|CrawlyProjectCrawler|KomodiaBot|KStandBot|CISPA Webcrawler|MTRobot|hyscore\.io|AlexandriaOrgBot|2ip bot|Yellowbrandprotectionbot|SEOlizer|vuhuvBot|INETDEX-BOT|Synapse|t3versionsBot|deepnoc|Cocolyzebot|hypestat|ReverseEngineeringBot|sempi\.tech|Iframely|MetaInspector|node-fetch|lkxscan|python-opengraph|OpenGraphCheck|developers\.google\.com\/\+\/web\/snippet|SenutoBot|MaCoCu|NewsBlur|inoreader|NetSystemsResearch|PageThing|WordPress\/|PhxBot|ImagesiftBot|Expanse|InternetMeasurement|^BW\/|GeedoBot|Audisto Crawler|PerplexityBot\/|[cC]laude[bB]ot|Monsidobot|GroupMeBot|Vercelbot|vercel-screenshot|facebookcatalog\/|meta-externalagent\/|meta-externalfetcher\/|AcademicBotRTU|KeybaseBot|Lemmy|CookieHubScan|Hydrozen\.io|HTTP Banner Detection|SummalyBot|MicrosoftPreview\/", // Media Manager - "cb_media_directoryRoot" : "/contentbox-custom/_content", - "cb_media_createFolders" : "true", - "cb_media_allowDelete" : "true", - "cb_media_allowDownloads" : "true", - "cb_media_allowUploads" : "true", - "cb_media_acceptMimeTypes" : "", - "cb_media_quickViewWidth" : "400", + "cb_media_directoryRoot" : "/contentbox-custom/_content", + "cb_media_createFolders" : "true", + "cb_media_allowDelete" : "true", + "cb_media_allowDownloads" : "true", + "cb_media_allowUploads" : "true", + "cb_media_acceptMimeTypes" : "", + "cb_media_quickViewWidth" : "400", // HTML5 Media Manager - "cb_media_html5uploads_maxFileSize" : "100", - "cb_media_html5uploads_maxFiles" : "25", + "cb_media_html5uploads_maxFileSize" : "100", + "cb_media_html5uploads_maxFiles" : "25", // Media Services - "cb_media_provider" : "CFContentMediaProvider", - "cb_media_provider_caching" : "true", + "cb_media_provider" : "CFContentMediaProvider", + "cb_media_provider_caching" : "true", // Editor Manager - "cb_editors_default" : "ckeditor", - "cb_editors_markup" : "HTML", - "cb_editors_ckeditor_toolbar" : "[ + "cb_editors_default" : "ckeditor", + "cb_editors_markup" : "HTML", + "cb_editors_ckeditor_toolbar" : "[ { ""name"": ""document"", ""items"" : [ ""Source"",""-"",""Maximize"",""ShowBlocks"" ] }, { ""name"": ""clipboard"", ""items"" : [ ""Cut"",""Copy"",""Paste"",""PasteText"",""PasteFromWord"",""-"",""Undo"",""Redo"" ] }, { ""name"": ""editing"", ""items"" : [ ""Find"",""Replace"",""SpellChecker""] }, @@ -165,7 +160,7 @@ component { ""name"": ""insert"", ""items"" : [ ""Image"",""Table"",""HorizontalRule"",""Smiley"",""SpecialChar"",""Iframe"",""InsertPre""] }, { ""name"": ""contentbox"", ""items"" : [ ""MediaEmbed"",""cbIpsumLorem"",""cbWidgets"",""cbContentStore"",""cbLinks"",""cbEntryLinks"" ] } ]", - "cb_editors_ckeditor_excerpt_toolbar" : " + "cb_editors_ckeditor_excerpt_toolbar": " [ { ""name"": ""document"", ""items"" : [ ""Source"",""-"",""Maximize"",""ShowBlocks"" ] }, { ""name"": ""basicstyles"", ""items"" : [ ""Bold"",""Italic"",""Underline"",""Strike"",""Subscript"",""Superscript""] }, @@ -174,58 +169,58 @@ component { ""name"": ""insert"", ""items"" : [ ""Image"",""Flash"",""Table"",""HorizontalRule"",""Smiley"",""SpecialChar"" ] }, { ""name"": ""contentbox"", ""items"" : [ ""MediaEmbed"",""cbIpsumLorem"",""cbWidgets"",""cbContentStore"",""cbLinks"",""cbEntryLinks"" ] } ]", - "cb_editors_ckeditor_extraplugins" : "cbKeyBinding,cbWidgets,cbLinks,cbEntryLinks,cbContentStore,cbIpsumLorem,wsc,mediaembed,insertpre,justify,colorbutton,showblocks,find,div,smiley,specialchar,iframe", + "cb_editors_ckeditor_extraplugins": "cbKeyBinding,cbWidgets,cbLinks,cbEntryLinks,cbContentStore,cbIpsumLorem,wsc,mediaembed,insertpre,justify,colorbutton,showblocks,find,div,smiley,specialchar,iframe", // Search Settings - "cb_search_adapter" : "contentbox.models.search.DBSearch", - "cb_search_maxResults" : "20", + "cb_search_adapter" : "contentbox.models.search.DBSearch", + "cb_search_maxResults" : "20", // Site Maintenance - "cb_site_maintenance_message" : "

      This site is down for maintenance.
      Please check back again soon.

      ", - "cb_site_maintenance" : "false", + "cb_site_maintenance_message" : "

      This site is down for maintenance.
      Please check back again soon.

      ", + "cb_site_maintenance" : "false", // Versioning - "cb_versions_max_history" : "", - "cb_versions_commit_mandatory" : "false" + "cb_versions_max_history" : "", + "cb_versions_commit_mandatory" : "false" }; // Site Defaults this.SITE_DEFAULTS = { // Global HTML: Panel Section - "cb_html_beforeHeadEnd" : "", - "cb_html_afterBodyStart" : "", - "cb_html_beforeBodyEnd" : "", - "cb_html_beforeContent" : "", - "cb_html_afterContent" : "", - "cb_html_beforeSideBar" : "", - "cb_html_afterSideBar" : "", - "cb_html_afterFooter" : "", - "cb_html_preEntryDisplay" : "", - "cb_html_postEntryDisplay" : "", - "cb_html_preIndexDisplay" : "", - "cb_html_postIndexDisplay" : "", - "cb_html_preArchivesDisplay" : "", - "cb_html_postArchivesDisplay" : "", - "cb_html_preCommentForm" : "", - "cb_html_postCommentForm" : "", - "cb_html_prePageDisplay" : "", - "cb_html_postPageDisplay" : "", + "cb_html_beforeHeadEnd" : "", + "cb_html_afterBodyStart" : "", + "cb_html_beforeBodyEnd" : "", + "cb_html_beforeContent" : "", + "cb_html_afterContent" : "", + "cb_html_beforeSideBar" : "", + "cb_html_afterSideBar" : "", + "cb_html_afterFooter" : "", + "cb_html_preEntryDisplay" : "", + "cb_html_postEntryDisplay" : "", + "cb_html_preIndexDisplay" : "", + "cb_html_postIndexDisplay" : "", + "cb_html_preArchivesDisplay" : "", + "cb_html_postArchivesDisplay" : "", + "cb_html_preCommentForm" : "", + "cb_html_postCommentForm" : "", + "cb_html_prePageDisplay" : "", + "cb_html_postPageDisplay" : "", // Site Comment Settings - "cb_comments_enabled" : "true", - "cb_comments_maxDisplayChars" : "500", - "cb_comments_notify" : "true", - "cb_comments_moderation_notify" : "true", - "cb_comments_notifyemails" : "", - "cb_comments_moderation" : "true", - "cb_comments_moderation_whitelist" : "true", - "cb_comments_moderation_blacklist" : "", - "cb_comments_moderation_blockedlist" : "", - "cb_comments_moderation_expiration" : "30" + "cb_comments_enabled" : "true", + "cb_comments_maxDisplayChars" : "500", + "cb_comments_notify" : "true", + "cb_comments_moderation_notify" : "true", + "cb_comments_notifyemails" : "", + "cb_comments_moderation" : "true", + "cb_comments_moderation_whitelist" : "true", + "cb_comments_moderation_blacklist" : "", + "cb_comments_moderation_blockedlist": "", + "cb_comments_moderation_expiration" : "30" }; /** * Constructor */ - SettingService function init(){ - variables.oSystem = createObject( "java", "java.lang.System" ); - variables.CBReadyFlag = false; + SettingService function init() { + variables.oSystem = createObject( "java", "java.lang.System" ); + variables.CBReadyFlag = false; variables.cacheProviderName = "template"; // init it @@ -238,17 +233,18 @@ component * This method will go over all system settings and make sure that there are no missing default core settings. * If they are, we will create the core settings with the appropriate defaults: this.DEFAULTS */ - SettingService function preFlightCheck(){ + SettingService function preFlightCheck() { // Log it variables.log.info( "> Running ContentBox pre flight checks..." ); var sTime = getTickCount(); // Iterate over default core settings and check they exist lock - name ="contentbox-pre-flight", - timeout = "10" + name ="contentbox-pre-flight" + timeout ="10" throwOnTimeout="true" - type ="exclusive" { + type ="exclusive" + { // Check what's missing for the global settings transaction { // Get all core, non-deleted settings @@ -256,68 +252,90 @@ component .isNull( "site" ) .isFalse( "isDeleted" ) .isTrue( "isCore" ) - .withProjections( property: "name" ) + .withProjections( property = "name" ) .list( sortOrder = "name" ); // Verify defaults exist - this.DEFAULTS + this + .DEFAULTS + .filter( + function( key, value ) { + return !arrayContainsNoCase( loadedSettings, arguments.key ); + } + ) // only process defaults that do not exist in the database - .filter( function( key, value ){ - return !arrayContainsNoCase( loadedSettings, arguments.key ); - } ) + // Create the missing global setting - .each( function( key, value ){ - variables.log.info( "- Missing core setting (#arguments.key#) found in pre-flight, adding it!" ); - entitySave( - this.new( { - name : arguments.key, - value : trim( arguments.value ), - isCore : true - } ) - ); - } ); + .each( + function( key, value ) { + variables.log.info( + "- Missing core setting (#arguments.key#) found in pre-flight, adding it!" + ); + entitySave( + this.new( + { + name : arguments.key, + value : trim( arguments.value ), + isCore: true + } + ) + ); + } + ); // Get all site core settings in the database var dbSiteSettings = newCriteria() .isFalse( "isDeleted" ) .isTrue( "isCore" ) .joinTo( "site", "site" ) - .withProjections( property: "name,site.slug:siteSlug" ) + .withProjections( property = "name,site.slug:siteSlug" ) .asStruct() .list( sortOrder = "site.slug,name" ); // Get all Sites and process them for core settings - variables.siteService + variables + .siteService .getAll() - .each( function( site ){ - var targetSite = arguments.site; - // Ensure Site Media Folder - variables.siteService.ensureSiteMediaFolder( targetSite ); - // Setup Site Settings - this.SITE_DEFAULTS - // only process defaults that do not exist in the database - .filter( function( key, value ){ - return arrayFilter( dbSiteSettings, function( item ){ - return ( - arguments.item[ "name" ] == key && arguments.item[ "siteSlug" ] == targetSite.getSlug() - ); - } ).isEmpty(); - } ) - // Create the missing site setting - .each( function( key, value ){ - variables.log.info( - "- Site (#targetSite.getSlug()#) missing setting (#arguments.key#), adding it!" - ); - entitySave( - this.new( { - name : arguments.key, - value : trim( arguments.value ), - isCore : true, - site : targetSite - } ) + .each( + function( site ) { + var targetSite = arguments.site; + + variables.siteService.ensureSiteMediaFolder( targetSite ); + + this + .SITE_DEFAULTS + .filter( + function( key, value ) { + return arrayFilter( + dbSiteSettings, + function( item ) { + return ( + arguments.item[ "name" ] == key && + arguments.item[ "siteSlug" ] == targetSite.getSlug() + ); + } + ).isEmpty(); + } + ) + .each( + function( key, value ) { + variables.log.info( + "- Site (#targetSite.getSlug()#) missing setting (#arguments.key#), adding it!" + ); + entitySave( + this.new( + { + name : arguments.key, + value : trim( arguments.value ), + isCore: true, + site : targetSite + } + ) + ); + } ); - } ); - } ); + } + ); } // end transaction @@ -325,7 +343,9 @@ component loadCacheProviderName(); } - variables.log.info( "√ ContentBox pre flight checks done in (#getTickCount() - sTime#)ms!" ); + variables.log.info( + "√ ContentBox pre flight checks done in (#getTickCount() - sTime#)ms!" + ); return this; } @@ -333,24 +353,29 @@ component /** * Get a collection (struct) of settings that represent the defaults for a site in ContentBox */ - struct function getSiteSettingDefaults(){ + struct function getSiteSettingDefaults() { return this.SITE_DEFAULTS; } /** * The static key used for caching all the settings of this installation */ - string function getSettingsCacheKey(){ - return "cb-settings-container-#reReplace( variables.appName, "\s", "-", "all" )#"; + string function getSettingsCacheKey() { + return "cb-settings-container-#reReplace( + variables.appName, + "\s", + "-", + "all" + )#"; } /** * Check if the installer is present */ - boolean function isInstallationPresent(){ + boolean function isInstallationPresent() { if ( - structKeyExists( variables.moduleSettings, "contentbox-installer" ) AND - directoryExists( variables.moduleSettings[ "contentbox-installer" ].path ) + structKeyExists( variables.moduleSettings, "contentbox-installer" ) && + directoryExists( variables.moduleSettings[ "contentbox-installer" ].path ) ) { return true; } @@ -361,10 +386,10 @@ component /** * Delete the installer module */ - boolean function deleteInstaller(){ + boolean function deleteInstaller() { if ( - structKeyExists( variables.moduleSettings, "contentbox-installer" ) AND - directoryExists( variables.moduleSettings[ "contentbox-installer" ].path ) + structKeyExists( variables.moduleSettings, "contentbox-installer" ) && + directoryExists( variables.moduleSettings[ "contentbox-installer" ].path ) ) { directoryDelete( variables.moduleSettings[ "contentbox-installer" ].path, true ); return true; @@ -376,7 +401,7 @@ component * Check if contentbox has been installed by checking if there are no settings and no cb_active ONLY * If the query comes back with active, it will not run it again. */ - boolean function isCBReady(){ + boolean function isCBReady() { // Short circuit caching if ( variables.CBReadyFlag ) { return true; @@ -396,8 +421,8 @@ component /** * Mark cb as ready to serve */ - SettingService function activateCB(){ - save( this.new( { name : "cb_active", value : "true" } ) ); + SettingService function activateCB() { + save( this.new( { name: "cb_active", value: "true" } ) ); return this; } @@ -411,7 +436,7 @@ component * * @throws SettingNotFoundException */ - function getSetting( required name, defaultValue ){ + function getSetting( required name, defaultValue ) { var allSettings = getAllSettings(); // verify it exists @@ -426,9 +451,9 @@ component // nothing we can do throw( - message: "Setting #arguments.name# not found in settings collection", - detail : "Registered settings are: #structKeyList( allSettings )#", - type : "SettingNotFoundException" + message = "Setting #arguments.name# not found in settings collection", + detail = "Registered settings are: #structKeyList( allSettings )#", + type = "SettingNotFoundException" ); } @@ -443,7 +468,7 @@ component * * @throws SettingNotFoundException */ - function getSiteSetting( required siteSlug, required name, defaultValue ){ + function getSiteSetting( required siteSlug, required name, defaultValue ) { var allSettings = getAllSiteSettings( arguments.siteSlug ); // verify it exists @@ -458,9 +483,9 @@ component // nothing we can do throw( - message: "Site setting #arguments.name# not found in site collection", - detail : "Registered settings are: #structKeyList( allSettings )#", - type : "SettingNotFoundException" + message = "Site setting #arguments.name# not found in site collection", + detail = "Registered settings are: #structKeyList( allSettings )#", + type = "SettingNotFoundException" ); } @@ -469,7 +494,7 @@ component * * @force To force clear the cache */ - struct function getAllSettings( boolean force = false ){ + struct function getAllSettings( boolean force = false ) { return getSettingsContainer( arguments.force ).global; } @@ -479,7 +504,7 @@ component * @slug The site slug to use to retrieve the settings * @force To force clear the cache */ - struct function getAllSiteSettings( required siteSlug, boolean force = false ){ + struct function getAllSiteSettings( required siteSlug, boolean force = false ) { return getSettingsContainer( arguments.force ).sites[ arguments.siteSlug ]; } @@ -488,7 +513,7 @@ component * * @force To force clear the cache */ - struct function getDefaultSiteSettings( boolean force = false ){ + struct function getDefaultSiteSettings( boolean force = false ) { return getSettingsContainer( arguments.force ).sites[ "default" ]; } @@ -497,7 +522,7 @@ component * * @force Force build */ - struct function getSettingsContainer( boolean force = false ){ + struct function getSettingsContainer( boolean force = false ) { // Force Clear if ( arguments.force ) { flushSettingsCache(); @@ -505,13 +530,13 @@ component // Get or set return getSettingsCacheProvider().getOrSet( - getSettingsCacheKey(), - function(){ - log.info( "Settings container not cached, rebuilding from DB!" ); - return buildSettingsContainer(); - }, - 7200 - ); + getSettingsCacheKey(), + function() { + log.info( "Settings container not cached, rebuilding from DB!" ); + return buildSettingsContainer(); + }, + 7200 + ); } /** @@ -522,7 +547,7 @@ component * * @return The setting object or null */ - function findSiteSetting( required site, required name ){ + function findSiteSetting( required site, required name ) { return newCriteria() .isEq( "site", arguments.site ) .isEq( "name", arguments.name ) @@ -534,14 +559,14 @@ component * * @return struct of { global : {}, sites : { slug : {} } } */ - struct function buildSettingsContainer(){ - var allSites = variables.siteService.getAllFlat(); - var container = { "global" : {}, "sites" : {} }; + struct function buildSettingsContainer() { + var allSites = variables.siteService.getAllFlat(); + var container = { "global": {}, "sites": {} }; // Initialize site setting containers from defaults container.sites = arrayReduce( allSites, - function( result, item ){ + function( result, item ) { result[ item[ "slug" ] ] = duplicate( this.SITE_DEFAULTS ); return result; }, @@ -552,14 +577,15 @@ component newCriteria() .isFalse( "isDeleted" ) .list( sortOrder = "site,name" ) - .each( function( item ){ - if ( item.hasSite() ) { - // Store the setting - container.sites[ item.getSite().getSlug() ][ item.getName() ] = item.getValue(); - } else { - container.global[ item.getName() ] = item.getValue(); + .each( + function( item ) { + if ( item.hasSite() ) { + container.sites[ item.getSite().getSlug() ][ item.getName() ] = item.getValue(); + } else { + container.global[ item.getName() ] = item.getValue(); + } } - } ); + ); return container; } @@ -568,20 +594,20 @@ component * This will store the incoming structure as the settings in cache. * Usually this method is used for major overrides. */ - SettingService function storeSettings( struct settings ){ + SettingService function storeSettings( struct settings ) { // cache them for 5 days, usually app timeout getSettingsCacheProvider().set( - getSettingsCacheKey(), - arguments.settings, - 7200 - ); + getSettingsCacheKey(), + arguments.settings, + 7200 + ); return this; } /** * flush settings cache for current multi-tenant host */ - SettingService function flushSettingsCache(){ + SettingService function flushSettingsCache() { // Info variables.log.info( "Settings Flush Executed!" ); // Clear out the settings cache @@ -604,39 +630,43 @@ component * * @return SettingService */ - SettingService function bulkSave( struct memento, site ){ - var settings = isNull( arguments.site ) ? getAllSettings() : getAllSiteSettings( arguments.site.getSlug() ); + SettingService function bulkSave( struct memento, site ) { + var settings = isNull( arguments.site ) ? getAllSettings() : getAllSiteSettings( arguments.site.getSlug() ); var newSettings = []; - arguments.memento + arguments + .memento + .filter( + function( key, value ) { + return settings.keyExists( key ); + } + ) // Only save, saveable keys - .filter( function( key, value ){ - return settings.keyExists( key ); - } ) + // Build out array of settings to save - .each( function( key, value ){ - var thisSetting = ""; - // Find the setting globally or by site, depending on the context - if ( isNull( site ) ) { - thisSetting = findWhere( { name : key } ); - } else { - thisSetting = findSiteSetting( site, key ); - } + .each( + function( key, value ) { + var thisSetting = ""; - // Maybe it's a new setting :) - if ( isNull( thisSetting ) ) { - thisSetting = new ( { name : key } ); - } + if ( isNull( site ) ) { + thisSetting = findWhere( { name: key } ); + } else { + thisSetting = findSiteSetting( site, key ); + } - thisSetting.setValue( toString( value ) ); + if ( isNull( thisSetting ) ) { + thisSetting = new( { name: key } ); + } - // Site mapping - if ( !isNull( site ) ) { - thisSetting.setSite( site ); - } + thisSetting.setValue( toString( value ) ); + + if ( !isNull( site ) ) { + thisSetting.setSite( site ); + } - newSettings.append( thisSetting ); - } ); + newSettings.append( thisSetting ); + } + ); // save new settings and flush cache saveAll( newSettings ); @@ -650,31 +680,31 @@ component * * @return struct */ - struct function buildFileBrowserSettings(){ + struct function buildFileBrowserSettings() { var cbSettings = getAllSettings(); - var settings = { - directoryRoot : expandPath( cbSettings.cb_media_directoryRoot ), - createFolders : cbSettings.cb_media_createFolders, - deleteStuff : cbSettings.cb_media_allowDelete, - allowDownload : cbSettings.cb_media_allowDownloads, - allowUploads : cbSettings.cb_media_allowUploads, - acceptMimeTypes : cbSettings.cb_media_acceptMimeTypes, - quickViewWidth : cbSettings.cb_media_quickViewWidth, - loadJQuery : false, - useMediaPath : true, - html5uploads : { - maxFileSize : cbSettings.cb_media_html5uploads_maxFileSize, - maxFiles : cbSettings.cb_media_html5uploads_maxFiles + var settings = { + directoryRoot : expandPath( cbSettings.cb_media_directoryRoot ), + createFolders : cbSettings.cb_media_createFolders, + deleteStuff : cbSettings.cb_media_allowDelete, + allowDownload : cbSettings.cb_media_allowDownloads, + allowUploads : cbSettings.cb_media_allowUploads, + acceptMimeTypes: cbSettings.cb_media_acceptMimeTypes, + quickViewWidth : cbSettings.cb_media_quickViewWidth, + loadJQuery : false, + useMediaPath : true, + html5uploads : { + maxFileSize: cbSettings.cb_media_html5uploads_maxFileSize, + maxFiles : cbSettings.cb_media_html5uploads_maxFiles } }; // Base MediaPath - var mediaPath = ""; + var mediaPath = ""; // add the entry point var entryPoint = moduleSettings[ "contentbox-ui" ].entryPoint; mediaPath &= ( len( entryPoint ) ? "#entryPoint#/" : "" ) & "__media"; // Store it - mediaPath = ( left( mediaPath, 1 ) == "/" ? mediaPath : "/" & mediaPath ); + mediaPath = ( left( mediaPath, 1 ) == "/" ? mediaPath : "/" & mediaPath ); settings.mediaPath = mediaPath; return settings; @@ -697,25 +727,30 @@ component offset = 0, sortOrder = "name asc", siteID = "" - ){ - var results = { "count" : 0, "settings" : [] }; - var c = newCriteria() - // Search Criteria - .when( len( arguments.search ), function( c ){ - c.like( "name", "%#search#%" ); - } ) + ) { + var results = { "count": 0, "settings": [] }; + var c = newCriteria().when( + len( arguments.search ), + function( c ) { + c.like( "name", "%#search#%" ); + } + )// Search Criteria + // Site Filter - .when( len( arguments.siteID ), function( c ){ - c.isEq( "site.siteID", siteID ); - } ); + .when( + len( arguments.siteID ), + function( c ) { + c.isEq( "site.siteID", siteID ); + } + ); // run criteria query and projections count - results.count = c.count( "settingID" ); + results.count = c.count( "settingID" ); results.settings = c.list( - offset : arguments.offset, - max : arguments.max, - sortOrder: arguments.sortOrder - ); + offset = arguments.offset, + max = arguments.max, + sortOrder = arguments.sortOrder + ); return results; } @@ -723,10 +758,12 @@ component /** * Get all data prepared for export */ - array function getAllForExport(){ - return getAll().map( function( thisItem ){ - return thisItem.getMemento( profile: "export" ); - } ); + array function getAllForExport() { + return getAll().map( + function( thisItem ) { + return thisItem.getMemento( profile = "export" ); + } + ); } /** @@ -739,14 +776,17 @@ component * * @throws InvalidImportFormat */ - string function importFromFile( required importFile, boolean override = false ){ - var data = fileRead( arguments.importFile ); + string function importFromFile( required importFile, boolean override = false ) { + var data = fileRead( arguments.importFile ); var importLog = createObject( "java", "java.lang.StringBuilder" ).init( - "Starting import with override = #arguments.override#...
      " - ); + "Starting import with override = #arguments.override#...
      " + ); if ( !isJSON( data ) ) { - throw( message = "Cannot import file as the contents is not JSON", type = "InvalidImportFormat" ); + throw( + message = "Cannot import file as the contents is not JSON", + type = "InvalidImportFormat" + ); } // deserialize packet: Should be array of { settingID, name, value } @@ -772,26 +812,28 @@ component required importData, boolean override = false, importLog - ){ + ) { var allSettings = []; var siteService = getWireBox().getInstance( "siteService@contentbox" ); // if struct, inflate into an array if ( isStruct( arguments.importData ) ) { - arguments.importData = [ arguments.importData ]; + arguments.importData = [ arguments.importData]; } transaction { // iterate and import for ( var thisSetting in arguments.importData ) { // Site Setting or Global Setting - var oSetting = findWhere( { - name : thisSetting.name, - site : isNull( thisSetting.site.siteID ) ? javacast( "null", "" ) : siteService.get( - thisSetting.site.siteID - ) - } ); - oSetting = ( isNull( oSetting ) ? new () : oSetting ); + var oSetting = findWhere( + { + name: thisSetting.name, + site: isNull( thisSetting.site.siteID ) + ? javacast( "null", "" ) + : siteService.get( thisSetting.site.siteID ) + } + ); + oSetting = ( isNull( oSetting ) ? new() : oSetting ); // Check for boolean values if ( isSimpleValue( thisSetting.value ) && isBoolean( thisSetting.value ) ) { @@ -800,11 +842,11 @@ component // populate content from data getBeanPopulator().populateFromStruct( - target : oSetting, - memento : thisSetting, - exclude : "settingID,site", - composeRelationships: false - ); + target = oSetting, + memento = thisSetting, + exclude = "settingID,site", + composeRelationships = false + ); // Link the site if it exists if ( !isNull( thisSetting.site.slug ) ) { @@ -815,7 +857,7 @@ component if ( !oSetting.isLoaded() ) { arguments.importLog.append( "New setting imported: #thisSetting.name#
      " ); arrayAppend( allSettings, oSetting ); - } else if ( oSetting.isLoaded() and arguments.override ) { + } else if ( oSetting.isLoaded() && arguments.override ) { arguments.importLog.append( "Persisted setting overriden: #thisSetting.name#
      " ); arrayAppend( allSettings, oSetting ); } else { @@ -830,8 +872,8 @@ component arguments.importLog.append( "Saved all imported and overriden settings!" ); } else { arguments.importLog.append( - "No settings imported as none where found or able to be overriden from the import file." - ); + "No settings imported as none where found or able to be overriden from the import file." + ); } } // end of transaction @@ -844,7 +886,7 @@ component * * @return coldbox.system.cache.ICacheProvider */ - function getSettingsCacheProvider(){ + function getSettingsCacheProvider() { // Return the cache to use return cacheBox.getCache( variables.cacheProviderName ); } @@ -852,19 +894,21 @@ component /** * Load up config overrides */ - function loadConfigOverrides(){ + function loadConfigOverrides() { // Global Settings if ( - structKeyExists( variables.contentboxSettings, "settings" ) - && - structKeyExists( variables.contentboxSettings.settings, "global" ) + structKeyExists( variables.contentboxSettings, "settings" ) && + structKeyExists( variables.contentboxSettings.settings, "global" ) ) { var settingsContainer = getSettingsContainer(); // Append and override structAppend( settingsContainer.global, - variables.contentboxSettings.settings.global, + variables + .contentboxSettings + .settings + .global, true ); @@ -872,12 +916,14 @@ component storeSettings( settingsContainer ); // Log it - variables.log.info( - "ContentBox global config overrides loaded.", - variables.contentboxSettings.settings.global - ); + variables.log.info( "ContentBox global config overrides loaded.", + variables + .contentboxSettings + .settings + .global ); } + // TODO: Site Settings } @@ -886,14 +932,18 @@ component * The pattern to look is `contentbox.{site}.{setting}` * Example: contentbox.default.cb_media_directoryRoot */ - function loadEnvironmentOverrides(){ + function loadEnvironmentOverrides() { var environmentSettings = variables.oSystem.getEnv(); - var overrides = {}; + var overrides = {}; // iterate and override for ( var thisKey in environmentSettings ) { if ( reFindNoCase( "^contentbox\_", thisKey ) ) { - overrides[ reReplaceNoCase( thisKey, "^contentbox\_", "" ) ] = environmentSettings[ thisKey ]; + overrides[ reReplaceNoCase( + thisKey, + "^contentbox\_", + "" + ) ] = environmentSettings[ thisKey ]; } } @@ -906,7 +956,11 @@ component var settingsContainer = getSettingsContainer(); // Append and override - structAppend( settingsContainer.global, overrides, true ); + structAppend( + settingsContainer.global, + overrides, + true + ); // Store them back in storeSettings( settingsContainer ); @@ -920,7 +974,7 @@ component /** * Load the cache provider name from DB or default value */ - private SettingService function loadCacheProviderName(){ + private SettingService function loadCacheProviderName() { // query db for cache name var oProvider = newCriteria().isEq( "name", "cb_site_settings_cache" ).get(); // Check if setting in DB already, else default it @@ -933,4 +987,4 @@ component return this; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/system/Site.cfc b/modules/contentbox/models/system/Site.cfc index 25703e9f3c..7c0df99339 100644 --- a/modules/contentbox/models/system/Site.cfc +++ b/modules/contentbox/models/system/Site.cfc @@ -6,647 +6,633 @@ * I model a ContentBox site for multi-site support */ component - persistent="true" - entityname="cbSite" - table ="cb_site" - extends ="contentbox.models.BaseEntity" - cachename ="cbSite" - cacheuse ="read-write" + persistent="true" + entityname="cbSite" + table="cb_site" + extends="contentbox.models.BaseEntity" + cachename="cbSite" + cacheuse="read-write" { - /* ********************************************************************* - ** DI - ********************************************************************* */ - - property - name ="contentService" - inject ="provider:contentService@contentbox" - persistent="false"; - - /* ********************************************************************* - ** PROPERTIES - ********************************************************************* */ - - property - name ="siteID" - column ="siteID" - fieldtype="id" - generator="uuid" - length ="36" - ormtype ="string" - update ="false"; - - property - name ="name" - column ="name" - ormtype="string" - notnull="true" - length ="255" - default=""; - - property - name ="slug" - column ="slug" - ormtype="string" - notnull="true" - length ="255" - unique ="true" - default="" - index ="idx_siteSlug"; - - property - name ="description" - column ="description" - ormtype="string" - notnull="false" - default="" - length ="500"; - - property - name ="keywords" - column ="keywords" - ormtype="string" - notnull="false" - default="" - length ="255"; - - property - name ="domain" - column ="domain" - ormtype="string" - notnull="false" - default="" - length ="255"; - - property - name ="domainRegex" - column ="domainRegex" - ormtype="string" - notnull="false" - default="" - length ="255"; - - property - name ="domainAliases" - column ="domainAliases" - ormtype="text" - notnull="false" - length ="8000" - default=""; - - property - name ="tagline" - column ="tagline" - ormtype="string" - notnull="false" - default="" - length ="255"; - - property - name ="homepage" - column ="homepage" - ormtype="string" - notnull="false" - default="cbBlog" - length ="255"; - - property - name ="isBlogEnabled" - column ="isBlogEnabled" - ormtype="boolean" - notnull="true" - default="true"; - - property - name ="isSitemapEnabled" - column ="isSitemapEnabled" - ormtype="boolean" - notnull="true" - default="true"; - - property - name ="poweredByHeader" - column ="poweredByHeader" - ormtype="boolean" - notnull="true" - default="true"; - - property - name ="adminBar" - column ="adminBar" - ormtype="boolean" - notnull="true" - default="true"; - - property - name ="isSSL" - column ="isSSL" - ormtype="boolean" - notnull="true" - default="false"; - - property - name ="isActive" - column ="isActive" - ormtype="boolean" - notnull="true" - default="true"; - - property - name ="activeTheme" - column ="activeTheme" - ormtype="string" - notnull="false" - default="" - length ="255"; - - property - name ="notificationEmails" - column ="notificationEmails" - ormtype="string" - notnull="false" - default="" - length ="500"; - - property - name ="notifyOnEntries" - column ="notifyOnEntries" - ormtype="boolean" - notnull="true" - default="true"; - - property - name ="notifyOnPages" - column ="notifyOnPages" - ormtype="boolean" - notnull="true" - default="true"; - - property - name ="notifyOnContentStore" - column ="notifyOnContentStore" - ormtype="boolean" - notnull="true" - default="true"; - - property - name ="mediaDisk" - column ="mediaDisk" - ormtype="string" - notnull="false" - default="contentbox" - length ="50"; - - /* ********************************************************************* - ** RELATIONSHIPS - ********************************************************************* */ - - // O2M -> Settings - property - name ="settings" - singularName="setting" - fieldtype ="one-to-many" - type ="array" - lazy ="true" - orderby ="name" - cfc ="contentbox.models.system.Setting" - fkcolumn ="FK_siteID" - inverse ="true" - cascade ="all-delete-orphan"; - - // O2M -> Categories - property - name ="categories" - singularName="category" - fieldtype ="one-to-many" - type ="array" - lazy ="true" - orderby ="slug" - cfc ="contentbox.models.content.Category" - fkcolumn ="FK_siteID" - inverse ="true" - cascade ="all-delete-orphan"; - - // O2M -> Entries - property - name ="entries" - singularName="entry" - fieldtype ="one-to-many" - type ="array" - lazy ="true" - orderby ="createdDate desc" - cfc ="contentbox.models.content.Entry" - fkcolumn ="FK_siteID" - inverse ="true" - cascade ="all-delete-orphan"; - - // O2M -> Pages - property - name ="pages" - singularName="page" - fieldtype ="one-to-many" - type ="array" - lazy ="true" - orderby ="parent" - cfc ="contentbox.models.content.Page" - fkcolumn ="FK_siteID" - inverse ="true" - cascade ="all-delete-orphan"; - - // O2M -> ContentStore - property - name ="contentStore" - fieldtype="one-to-many" - type ="array" - lazy ="true" - orderby ="parent" - cfc ="contentbox.models.content.ContentStore" - fkcolumn ="FK_siteID" - inverse ="true" - cascade ="all-delete-orphan"; - - // O2M -> menus - property - name ="menus" - singularName="menu" - fieldtype ="one-to-many" - type ="array" - lazy ="true" - orderby ="createdDate desc" - cfc ="contentbox.models.menu.Menu" - fkcolumn ="FK_siteID" - inverse ="true" - cascade ="all-delete-orphan"; - - /* ********************************************************************* - ** CALUCLATED FIELDS - ********************************************************************* */ - - property - name ="numberOfEntries" - formula="select count(*) + /********************************************************************** + * ** DI + **********************************************************************/ + + property name="contentService" inject="provider:contentService@contentbox" persistent="false"; + + /********************************************************************** + * ** PROPERTIES + **********************************************************************/ + + property + name="siteID" + column="siteID" + fieldtype="id" + generator="uuid" + length="36" + ormtype="string" + update="false"; + + property + name="name" + column="name" + ormtype="string" + notnull="true" + length="255" + default=""; + + property + name="slug" + column="slug" + ormtype="string" + notnull="true" + length="255" + unique="true" + default="" + index="idx_siteSlug"; + + property + name="description" + column="description" + ormtype="string" + notnull="false" + default="" + length="500"; + + property + name="keywords" + column="keywords" + ormtype="string" + notnull="false" + default="" + length="255"; + + property + name="domain" + column="domain" + ormtype="string" + notnull="false" + default="" + length="255"; + + property + name="domainRegex" + column="domainRegex" + ormtype="string" + notnull="false" + default="" + length="255"; + + property + name="domainAliases" + column="domainAliases" + ormtype="text" + notnull="false" + length="8000" + default=""; + + property + name="tagline" + column="tagline" + ormtype="string" + notnull="false" + default="" + length="255"; + + property + name="homepage" + column="homepage" + ormtype="string" + notnull="false" + default="cbBlog" + length="255"; + + property + name="isBlogEnabled" + column="isBlogEnabled" + ormtype="boolean" + notnull="true" + default="true"; + + property + name="isSitemapEnabled" + column="isSitemapEnabled" + ormtype="boolean" + notnull="true" + default="true"; + + property + name="poweredByHeader" + column="poweredByHeader" + ormtype="boolean" + notnull="true" + default="true"; + + property + name="adminBar" + column="adminBar" + ormtype="boolean" + notnull="true" + default="true"; + + property + name="isSSL" + column="isSSL" + ormtype="boolean" + notnull="true" + default="false"; + + property + name="isActive" + column="isActive" + ormtype="boolean" + notnull="true" + default="true"; + + property + name="activeTheme" + column="activeTheme" + ormtype="string" + notnull="false" + default="" + length="255"; + + property + name="notificationEmails" + column="notificationEmails" + ormtype="string" + notnull="false" + default="" + length="500"; + + property + name="notifyOnEntries" + column="notifyOnEntries" + ormtype="boolean" + notnull="true" + default="true"; + + property + name="notifyOnPages" + column="notifyOnPages" + ormtype="boolean" + notnull="true" + default="true"; + + property + name="notifyOnContentStore" + column="notifyOnContentStore" + ormtype="boolean" + notnull="true" + default="true"; + + property + name="mediaDisk" + column="mediaDisk" + ormtype="string" + notnull="false" + default="contentbox" + length="50"; + + /********************************************************************** + * ** RELATIONSHIPS + **********************************************************************/ + + // O2M -> Settings + property + name="settings" + singularName="setting" + fieldtype="one-to-many" + type="array" + lazy="true" + orderby="name" + cfc="contentbox.models.system.Setting" + fkcolumn="FK_siteID" + inverse="true" + cascade="all-delete-orphan"; + + // O2M -> Categories + property + name="categories" + singularName="category" + fieldtype="one-to-many" + type="array" + lazy="true" + orderby="slug" + cfc="contentbox.models.content.Category" + fkcolumn="FK_siteID" + inverse="true" + cascade="all-delete-orphan"; + + // O2M -> Entries + property + name="entries" + singularName="entry" + fieldtype="one-to-many" + type="array" + lazy="true" + orderby="createdDate desc" + cfc="contentbox.models.content.Entry" + fkcolumn="FK_siteID" + inverse="true" + cascade="all-delete-orphan"; + + // O2M -> Pages + property + name="pages" + singularName="page" + fieldtype="one-to-many" + type="array" + lazy="true" + orderby="parent" + cfc="contentbox.models.content.Page" + fkcolumn="FK_siteID" + inverse="true" + cascade="all-delete-orphan"; + + // O2M -> ContentStore + property + name="contentStore" + fieldtype="one-to-many" + type="array" + lazy="true" + orderby="parent" + cfc="contentbox.models.content.ContentStore" + fkcolumn="FK_siteID" + inverse="true" + cascade="all-delete-orphan"; + + // O2M -> menus + property + name="menus" + singularName="menu" + fieldtype="one-to-many" + type="array" + lazy="true" + orderby="createdDate desc" + cfc="contentbox.models.menu.Menu" + fkcolumn="FK_siteID" + inverse="true" + cascade="all-delete-orphan"; + + /********************************************************************** + * ** CALUCLATED FIELDS + **********************************************************************/ + + property + name="numberOfEntries" + formula="select count(*) from cb_entry as entry, cb_content as content where entry.contentID=content.contentID and content.FK_siteID = siteID"; - property - name ="numberOfPages" - formula="select count(*) + property + name="numberOfPages" + formula="select count(*) from cb_page as page, cb_content as content where page.contentID=content.contentID and content.FK_siteID = siteID"; - property - name ="numberOfContentStore" - formula="select count(*) + property + name="numberOfContentStore" + formula="select count(*) from cb_contentStore as contentStore, cb_content as content where contentStore.contentID=content.contentID and content.FK_siteID = siteID"; - property - name ="numberOfMenus" - formula="select count(*) + property + name="numberOfMenus" + formula="select count(*) from cb_menu as menu where menu.FK_siteID = siteID"; - property - name ="numberOfCategories" - formula="select count(*) + property + name="numberOfCategories" + formula="select count(*) from cb_category as category where category.FK_siteID = siteID"; - - /* ********************************************************************* - ** PK + CONSTRAINTS + MEMENTO - ********************************************************************* */ - - this.pk = "siteID"; - - this.memento = { - defaultIncludes : [ - "activeTheme", - "adminBar", - "description", - "domain", - "domainregex", - "domainAliases", - "homepage", - "isActive", - "isBlogEnabled", - "isSitemapEnabled", - "isSSL", - "keywords", - "name", - "notificationEmails", - "notifyOnContentStore", - "notifyOnEntries", - "notifyOnPages", - "numberOfCategories", - "numberOfContentStore", - "numberOfEntries", - "numberOfMenus", - "numberOfPages", - "poweredByHeader", - "slug", - "tagline" - ], - defaultExcludes : [ - "categories", - "contentStore", - "entries", - "menus", - "pages", - "settings" - ], - profiles : { - export : { - defaultIncludes : [ - "categories", - "contentStore", - "entries", - "menus", - "pages", - "settings" - ], - defaultExcludes : [ - "settings.siteSnapshot", - "menus.siteSnapshot:site" - ] - } - } - }; - - this.constraints = { - "name" : { required : true, size : "2..255" }, - "slug" : { - required : true, - size : "2..255", - validator : "UniqueValidator@cborm" - }, - "description" : { required : false, size : "0..500" }, - "keywords" : { required : false, size : "0..255" }, - "domain" : { required : true, size : "1..255" }, - "domainRegex" : { required : true, size : "1..255" }, - "domainAliases" : { required : false, type : "array" }, - "tagline" : { required : false, size : "0..255" }, - "homepage" : { required : false, size : "0..255" }, - "isBlogEnabled" : { required : true, type : "boolean" }, - "isSitemapEnabled" : { required : true, type : "boolean" }, - "poweredByHeader" : { required : true, type : "boolean" }, - "adminBar" : { required : true, type : "boolean" }, - "isSSL" : { required : true, type : "boolean" }, - "isActive" : { required : true, type : "boolean" }, - "activeTheme" : { required : true, size : "0..255" } - }; - - /* ********************************************************************* - ** PUBLIC METHODS - ********************************************************************* */ - - /** - * Constructor - */ - function init(){ - variables.settings = []; - variables.categories = []; - variables.entries = []; - variables.pages = []; - variables.contentStore = []; - variables.domainAliases = "[]"; - - super.init(); - - // Incorporate all includes to the export profile - this.memento.profiles.export.defaultIncludes.append( this.memento.defaultIncludes, true ); - - return this; - } - - /** - * Get the total number of content items in this site - */ - numeric function getNumberOfContent(){ - return variables.contentService.getTotalContentCount( getsiteID() ); - } - - /** - * I remove all setting associations - */ - Site function removeAllSettings(){ - if ( hasSetting() ) { - variables.settings.clear(); - } else { - variables.settings = []; - } - return this; - } - - /** - * I remove all category associations - */ - Site function removeAllCategories(){ - if ( hasCategory() ) { - variables.categories.clear(); - } else { - variables.categories = []; - } - return this; - } - - /** - * I remove all entry associations - */ - Site function removeAllEntries(){ - if ( hasEntry() ) { - variables.entries.clear(); - } else { - variables.entries = []; - } - return this; - } - - /** - * I remove all menu associations - */ - Site function removeAllMenus(){ - if ( hasMenu() ) { - variables.menus.clear(); - } else { - variables.menus = []; - } - return this; - } - - /** - * I remove all page associations - */ - Site function removeAllPages(){ - if ( hasPage() ) { - variables.pages.clear(); - } else { - variables.pages = []; - } - return this; - } - - /** - * I remove all contentStore associations - */ - Site function removeAllContentStore(){ - if ( hasContentStore() ) { - variables.contentStore.clear(); - } else { - variables.contentStore = []; - } - return this; - } - - /** - * Get the site root URL as defined per the settings - */ - String function getSiteRoot(){ - var serverPort = getServerPort(); - var domainName = this.getDomain(); - - // Return the appropriate site alias Uri from the domain aliases - // If the domain alias matches the incoming server host name - if ( - getDomainAliases().some( ( alias ) => alias.keyExists( "domainRegex" ) && reFindNoCase( alias.domainRegex, this.getServerName() ) ) - ) { - domainName = this.getServerName(); - } - - // Return the appropriate site Uri - return arrayToList( - [ - "http", - ( this.getIsSSL() ? "s" : "" ), - "://", - domainName, - ( listFind( "80,443", serverPort ) ? "" : ":#serverPort#" ) - ], - "" - ); - } - - /** - * Get the server port according to lookup order - * 1. x-forwarded-port header - * 2. cgi.server_port - */ - private function getServerPort(){ - var headers = getHTTPRequestData( false ).headers; - if ( structKeyExists( headers, "x-forwarded-port" ) && len( headers[ "x-forwarded-port" ] ) ) { - return headers[ "x-forwarded-port" ]; - } - return cgi.server_port; - } - - /** - * Get the server host according to lookup order - * 1. x-forwarded-host header - * 2. cgi.server_host - */ - private function getServerName(){ - var headers = getHTTPRequestData( false ).headers; - if ( structKeyExists( headers, "x-forwarded-host" ) && len( headers[ "x-forwarded-host" ] ) ) { - return headers[ "x-forwarded-host" ]; - } - return cgi.server_name; - } - - /** - * A nice snapshot of this entity used for mementifications - */ - struct function getInfoSnapshot(){ - if ( isLoaded() ) { - return { - "siteID" : getId(), - "slug" : getSlug(), - "name" : getName() - }; - } - return {}; - } - - /** - * Tries to get a category object by slug if assigned to this site - * - * @return The category object or null if not found - */ - function getCategory( required slug ){ - if ( hasCategory() ) { - var aFound = variables.categories.filter( function( thisCategory ){ - return arguments.thisCategory.getSlug() == slug; - } ); - if ( aFound.len() ) { - return aFound[ 1 ]; - } - } - } - - /** - * We make sure we only return pages that have no parent to simulate the root hierarchy. - * - * @override - * @root Show only root level pages if enabled - */ - function getPages( boolean root = true ){ - if ( !arguments.root ) { - return variables.pages; - } - return variables.pages.filter( function( thisPage ){ - return !arguments.thisPage.hasParent(); - } ); - } - - /** - * We make sure we only return contentStore that have no parent to simulate the root hierarchy. - * - * @override - * @root Show only root level contentStore if enabled - */ - function getContentStore( boolean root = true ){ - if ( !arguments.root ) { - return variables.contentStore; - } - return variables.contentStore.filter( function( thisContent ){ - return !arguments.thisContent.hasParent(); - } ); - } - - /** - * Get the domain aliases - * - * @return The domain aliases as an array - */ - array function getDomainAliases(){ - return ( - !isNull( variables.domainAliases ) AND isJSON( variables.domainAliases ) ? deserializeJSON( - variables.domainAliases - ) : [] - ); - } - - /** - * Get the domain aliases as a string - * - * @return The domain aliases as a json string - */ - string function getDomainAliasesAsJSON(){ - return isNull( variables.domainAliases ) ? "[]" : variables.domainAliases; - } - - /** - * Set the domain aliases. If the value is an array, it will be serialized to JSON - * as domain aliases are stored as a JSON string. - * - * @aliases The domain aliases as an array or a JSON array string - */ - Site function setDomainAliases( any aliases = [] ){ - variables.domainAliases = isSimpleValue( arguments.aliases ) ? arguments.aliases : serializeJSON( - arguments.aliases - ); - return this; - } + /********************************************************************** + * ** PK + CONSTRAINTS + MEMENTO + **********************************************************************/ + + this.pk = 'siteID'; + + this.memento = { + defaultIncludes: [ + 'activeTheme', + 'adminBar', + 'description', + 'domain', + 'domainregex', + 'domainAliases', + 'homepage', + 'isActive', + 'isBlogEnabled', + 'isSitemapEnabled', + 'isSSL', + 'keywords', + 'name', + 'notificationEmails', + 'notifyOnContentStore', + 'notifyOnEntries', + 'notifyOnPages', + 'numberOfCategories', + 'numberOfContentStore', + 'numberOfEntries', + 'numberOfMenus', + 'numberOfPages', + 'poweredByHeader', + 'slug', + 'tagline' + ], + defaultExcludes: [ + 'categories', + 'contentStore', + 'entries', + 'menus', + 'pages', + 'settings' + ], + profiles: { + export: { + defaultIncludes: [ + 'categories', + 'contentStore', + 'entries', + 'menus', + 'pages', + 'settings' + ], + defaultExcludes: ['settings.siteSnapshot', 'menus.siteSnapshot:site'] + } + } + }; + + this.constraints = { + 'name': {required: true, size: '2..255'}, + 'slug': {required: true, size: '2..255', validator: 'UniqueValidator@cborm'}, + 'description': {required: false, size: '0..500'}, + 'keywords': {required: false, size: '0..255'}, + 'domain': {required: true, size: '1..255'}, + 'domainRegex': {required: true, size: '1..255'}, + 'domainAliases': {required: false, type: 'array'}, + 'tagline': {required: false, size: '0..255'}, + 'homepage': {required: false, size: '0..255'}, + 'isBlogEnabled': {required: true, type: 'boolean'}, + 'isSitemapEnabled': {required: true, type: 'boolean'}, + 'poweredByHeader': {required: true, type: 'boolean'}, + 'adminBar': {required: true, type: 'boolean'}, + 'isSSL': {required: true, type: 'boolean'}, + 'isActive': {required: true, type: 'boolean'}, + 'activeTheme': {required: true, size: '0..255'} + }; + + /********************************************************************** + * ** PUBLIC METHODS + **********************************************************************/ + + /** + * Constructor + */ + function init() { + variables.settings = []; + variables.categories = []; + variables.entries = []; + variables.pages = []; + variables.contentStore = []; + variables.domainAliases = '[]'; + + super.init(); + + // Incorporate all includes to the export profile + this.memento.profiles.export.defaultIncludes.append(this.memento.defaultIncludes, true); + + return this; + } + + /** + * Get the total number of content items in this site + */ + numeric function getNumberOfContent() { + return variables.contentService.getTotalContentCount(getsiteID()); + } + + /** + * I remove all setting associations + */ + Site function removeAllSettings() { + if (hasSetting()) { + variables.settings.clear(); + } else { + variables.settings = []; + } + return this; + } + + /** + * I remove all category associations + */ + Site function removeAllCategories() { + if (hasCategory()) { + variables.categories.clear(); + } else { + variables.categories = []; + } + return this; + } + + /** + * I remove all entry associations + */ + Site function removeAllEntries() { + if (hasEntry()) { + variables.entries.clear(); + } else { + variables.entries = []; + } + return this; + } + + /** + * I remove all menu associations + */ + Site function removeAllMenus() { + if (hasMenu()) { + variables.menus.clear(); + } else { + variables.menus = []; + } + return this; + } + + /** + * I remove all page associations + */ + Site function removeAllPages() { + if (hasPage()) { + variables.pages.clear(); + } else { + variables.pages = []; + } + return this; + } + + /** + * I remove all contentStore associations + */ + Site function removeAllContentStore() { + if (hasContentStore()) { + variables.contentStore.clear(); + } else { + variables.contentStore = []; + } + return this; + } + + /** + * Get the site root URL as defined per the settings + */ + string function getSiteRoot() { + var serverPort = getServerPort(); + var domainName = this.getDomain(); + + // Return the appropriate site alias Uri from the domain aliases + // If the domain alias matches the incoming server host name + if ( + getDomainAliases().some((alias) => alias.keyExists('domainRegex') && + reFindNoCase(alias.domainRegex, getServerName())) + ) { + domainName = getServerName(); + } + + // Return the appropriate site Uri + return arrayToList( + [ + 'http', + (this.getIsSSL() ? 's' : ''), + '://', + domainName, + (listFind('80,443', serverPort) ? '' : ':#serverPort#') + ], + '' + ); + } + + /** + * A nice snapshot of this entity used for mementifications + */ + struct function getInfoSnapshot() { + if (isLoaded()) { + return {'siteID': getId(), 'slug': getSlug(), 'name': getName()}; + } + return {}; + } + + /** + * Tries to get a category object by slug if assigned to this site + * + * @return The category object or null if not found + */ + function getCategory(required slug) { + if (hasCategory()) { + var aFound = variables.categories.filter(function(thisCategory) { + return arguments.thisCategory.getSlug() == slug; + }); + if (aFound.len()) { + return aFound[1]; + } + } + } + + /** + * We make sure we only return pages that have no parent to simulate the root hierarchy. + * + * @override + * @root Show only root level pages if enabled + */ + function getPages(boolean root = true) { + if (!arguments.root) { + return variables.pages; + } + return variables.pages.filter(function(thisPage) { + return !arguments.thisPage.hasParent(); + }); + } + + /** + * We make sure we only return contentStore that have no parent to simulate the root hierarchy. + * + * @override + * @root Show only root level contentStore if enabled + */ + function getContentStore(boolean root = true) { + if (!arguments.root) { + return variables.contentStore; + } + return variables.contentStore.filter(function(thisContent) { + return !arguments.thisContent.hasParent(); + }); + } + + /** + * Get the domain aliases + * + * @return The domain aliases as an array + */ + array function getDomainAliases() { + return ( + !isNull(variables.domainAliases) && isJSON(variables.domainAliases) + ? deserializeJSON(variables.domainAliases) + : [] + ); + } + + /** + * Get the domain aliases as a string + * + * @return The domain aliases as a json string + */ + string function getDomainAliasesAsJSON() { + return isNull(variables.domainAliases) ? '[]' : variables.domainAliases; + } + + /** + * Set the domain aliases. If the value is an array, it will be serialized to JSON + * as domain aliases are stored as a JSON string. + * + * @aliases The domain aliases as an array or a JSON array string + */ + Site function setDomainAliases(any aliases = []) { + variables.domainAliases = isSimpleValue(arguments.aliases) + ? arguments.aliases + : serializeJSON(arguments.aliases); + return this; + } + + /** + * Get the server port according to lookup order + * 1. x-forwarded-port header + * 2. cgi.server_port + */ + private function getServerPort() { + var headers = getHTTPRequestData(false).headers; + if (structKeyExists(headers, 'x-forwarded-port') && len(headers['x-forwarded-port'])) { + return headers['x-forwarded-port']; + } + return cgi.server_port; + } + + /** + * Get the server host according to lookup order + * 1. x-forwarded-host header + * 2. cgi.server_host + */ + private function getServerName() { + var headers = getHTTPRequestData(false).headers; + if (structKeyExists(headers, 'x-forwarded-host') && len(headers['x-forwarded-host'])) { + return headers['x-forwarded-host']; + } + return cgi.server_name; + } } diff --git a/modules/contentbox/models/system/SiteService.cfc b/modules/contentbox/models/system/SiteService.cfc index f48315eef0..b4b77f0de0 100644 --- a/modules/contentbox/models/system/SiteService.cfc +++ b/modules/contentbox/models/system/SiteService.cfc @@ -5,30 +5,34 @@ * --- * Manage sites in ContentBox */ -component - extends ="cborm.models.VirtualEntityService" - accessors="true" - threadsafe - singleton -{ - +component extends ="cborm.models.VirtualEntityService" accessors="true" threadsafe singleton { // DI property name="cacheStorage" inject="cacheStorage@cbStorages"; + property name="cookieStorage" inject="cookieStorage@cbStorages"; + property name="requestStorage" inject="requestStorage@cbStorages"; + property name="loadedModules" inject="coldbox:setting:modules"; + property name="requestService" inject="coldbox:requestService"; + property name="settingService" inject="provider:settingService@contentbox"; + property name="categoryService" inject="provider:categoryService@contentbox"; + property name="contentService" inject="provider:contentService@contentbox"; + property name="menuService" inject="provider:menuService@contentbox"; + property name="themeService" inject="provider:themeService@contentbox"; + property name="mediaService" inject="provider:mediaService@contentbox"; /** * Constructor */ - SiteService function init(){ + SiteService function init() { // init it super.init( entityName = "cbSite" ); return this; @@ -39,12 +43,12 @@ component * * @siteID The site to store as the current working one */ - SiteService function setCurrentWorkingsiteID( required siteID ){ + SiteService function setCurrentWorkingsiteID( required siteID ) { variables.cookieStorage.set( - name : "contentbox_admin_current_site", - value : arguments.siteID, - expires: "never" - ); + name = "contentbox_admin_current_site", + value = arguments.siteID, + expires = "never" + ); return this; } @@ -52,33 +56,36 @@ component * Get the current working site in the admin UI. We look in the cache first, * if none is set, we use the `default` site. */ - function getCurrentWorkingsiteID(){ - return variables.cookieStorage.get( name: "contentbox_admin_current_site", defaultValue: getDefaultsiteID() ); + function getCurrentWorkingsiteID() { + return variables.cookieStorage.get( + name = "contentbox_admin_current_site", + defaultValue = getDefaultsiteID() + ); } /** * Get the current working site in the admin UI. We look in the cache first, * if none is set, we use the `default` site. */ - Site function getCurrentWorkingSite(){ + Site function getCurrentWorkingSite() { // Use request storage for acceleration return variables.requestStorage.getOrSet( - name : "contentbox-current-working-site", - produce: function(){ - var oSite = newCriteria().isEq( "siteID", getCurrentWorkingsiteID() ).get(); - // Check if null, just in case - return ( !isNull( oSite ) ? oSite : getDefaultSite() ); - } - ); + name = "contentbox-current-working-site", + produce = function() { + var oSite = newCriteria().isEq( "siteID", getCurrentWorkingsiteID() ).get(); + + return ( !isNull( oSite ) ? oSite : getDefaultSite() ); + } + ); } /** * Get the default site Identifier */ - string function getDefaultsiteID(){ + string function getDefaultsiteID() { return newCriteria() .isEq( "slug", "default" ) - .withProjections( property: "siteID" ) + .withProjections( property = "siteID" ) .get(); } @@ -87,56 +94,16 @@ component * we make sure all proper settings are created and configured. * * @site A persisted or new site object - * @transactional Transaction the call or leave as is, useful for imports, bulk saves, etc. */ - Site function save( required site, boolean transactional = true ){ - // Added this due to issue in CFML engines and mixed quuery+orm nested transactions. Remove once issue is fixed - if ( arguments.transactional ) { - transaction { - _save( arguments.site ); - } - } else { - _save( arguments.site ); + Site function save( required site ) { + transaction { + _save( arguments.site ) } // flush cache to rebuild site settings - variables.settingService.flushSettingsCache(); - - return arguments.site; - } - - /** - * Save operation called by the transactional `save()` method - * Due to transactional issues on Lucee - */ - private function _save( required site ){ - // Create all site settings if this is a new site - if ( !arguments.site.isLoaded() ) { - variables.settingService.saveAll( - variables.settingService - .getSiteSettingDefaults() - .reduce( function( result, setting, value ){ - arguments.result.append( - variables.settingService.new( { - name : arguments.setting, - value : trim( arguments.value ), - isCore : true, - site : site - } ) - ); - return arguments.result; - }, [] ) - ); - } + variables.settingService.flushSettingsCache() - // Persist the site - super.save( arguments.site ); - - // Activate the site's theme - variables.themeService.startupTheme( name: arguments.site.getActiveTheme(), site: arguments.site ); - - // Create media root folder for the site - ensureSiteMediaFolder( arguments.site ); + return arguments.site } /** @@ -147,8 +114,8 @@ component * * @return True if it created it, false if it already existed. */ - boolean function ensureSiteMediaFolder( required site ){ - var siteRoot = variables.mediaService.getCoreMediaRoot( absolute: true ) & "/sites/" & arguments.site.getSlug(); + boolean function ensureSiteMediaFolder( required site ) { + var siteRoot = variables.mediaService.getCoreMediaRoot( absolute = true ) & "/sites/" & arguments.site.getSlug(); if ( !directoryExists( siteRoot ) ) { directoryCreate( siteRoot ); return true; @@ -161,16 +128,17 @@ component * * @site The site to remove */ - SiteService function delete( required site ){ + SiteService function delete( required site ) { transaction { // If on Adobe, run hard deletes due to Hibernate issue with cascade on integration tests. if ( !server.keyExists( "lucee" ) ) { - variables.settingService.deleteWhere( site: arguments.site ); - variables.contentService.deleteWhere( site: arguments.site ); - variables.categoryService.deleteWhere( site: arguments.site ); - variables.menuService.deleteWhere( site: arguments.site ); + variables.settingService.deleteWhere( site = arguments.site ); + variables.contentService.deleteWhere( site = arguments.site ); + variables.categoryService.deleteWhere( site = arguments.site ); + variables.menuService.deleteWhere( site = arguments.site ); } - arguments.site + arguments + .site .removeAllSettings() .removeAllEntries() .removeAllPages() @@ -188,7 +156,7 @@ component /** * Get the default site object */ - Site function getDefaultSite(){ + Site function getDefaultSite() { return newCriteria().isEq( "slug", "default" ).get(); } @@ -199,12 +167,17 @@ component * * @return array of { siteID, name, slug, domainRegex, domainAliases, isActive } */ - array function getAllFlat( boolean isActive ){ + array function getAllFlat( boolean isActive ) { return newCriteria() - .when( !isNull( arguments.isActive ), function( c ){ - arguments.c.isEq( "this.isActive", javacast( "boolean", isActive ) ); - } ) - .withProjections( property: "siteID,name,slug,domainRegex,domainAliases,isActive" ) + .when( + !isNull( arguments.isActive ), + function( c ) { + arguments.c.isEq( "this.isActive", javacast( "boolean", isActive ) ); + } + ) + .withProjections( + property = "siteID,name,slug,domainRegex,domainAliases,isActive" + ) .asStruct() .list( sortOrder = "name" ); } @@ -214,10 +187,10 @@ component * * @return array of { activeTheme:string, siteID:numeric } */ - array function getAllSiteThemes(){ + array function getAllSiteThemes() { return newCriteria() .isFalse( "isDeleted" ) - .withProjections( distinct: "activeTheme,siteID" ) + .withProjections( distinct = "activeTheme,siteID" ) .asStruct() .list( sortOrder = "siteID" ); } @@ -229,14 +202,17 @@ component * * @throws EntityNotFound */ - function getOrFail( required siteID ){ + function getOrFail( required siteID ) { var site = newCriteria().isEq( "siteID", arguments.siteID ).get(); if ( !isNull( site ) ) { return site; } - throw( type: "EntityNotFound", message: "No site with ID #arguments.siteID.toString()# found" ); + throw( + type = "EntityNotFound", + message = "No site with ID #arguments.siteID.toString()# found" + ); } /** @@ -246,14 +222,17 @@ component * * @throws EntityNotFound */ - function getBySlugOrFail( required slug ){ + function getBySlugOrFail( required slug ) { var site = newCriteria().isEq( "slug", arguments.slug ).get(); if ( !isNull( site ) ) { return site; } - throw( type: "EntityNotFound", message: "No site with slug #arguments.slug.toString()# found" ); + throw( + type = "EntityNotFound", + message = "No site with slug #arguments.slug.toString()# found" + ); } /** @@ -267,14 +246,13 @@ component * * @return The site object */ - Site function discoverSite(){ + Site function discoverSite() { var event = variables.requestService.getContext(); // Are we in the admin? if ( - structKeyExists( variables.loadedModules, "contentbox-admin" ) - && - findNoCase( variables.loadedModules[ "contentbox-admin" ].entryPoint, event.getCurrentRoutedUrl() ) + structKeyExists( variables.loadedModules, "contentbox-admin" ) && + findNoCase( variables.loadedModules[ "contentbox-admin" ].entryPoint, event.getCurrentRoutedUrl() ) ) { return getCurrentWorkingSite(); } @@ -306,23 +284,27 @@ component // Try to discover using the requested full URL including host + path + query string for added flexibility // Verify the site is valid, else continue search - var matchedSite = getAllFlat( isActive: true ).filter( function( thisSite ){ - // direct regex match - if ( reFindNoCase( arguments.thisSite[ "domainRegex" ], event.getFullUrl() ) ) { - return true; - } - - // Look at the site Domain Aliases for a match - if ( isJSON( arguments.thisSite[ "domainAliases" ] ) ) { - return arraySome( deserializeJSON( arguments.thisSite[ "domainAliases" ] ), function( alias ){ - return ( - structKeyExists( alias, "domainRegex" ) && reFindNoCase( alias.domainRegex, event.getFullUrl() ) - ); - } ); - } + var matchedSite = getAllFlat( isActive = true ).filter( + function( thisSite ) { + if ( reFindNoCase( arguments.thisSite[ "domainRegex" ], event.getFullUrl() ) ) { + return true; + } + + if ( isJSON( arguments.thisSite[ "domainAliases" ] ) ) { + return arraySome( + deserializeJSON( arguments.thisSite[ "domainAliases" ] ), + function( alias ) { + return ( + structKeyExists( alias, "domainRegex" ) && + reFindNoCase( alias.domainRegex, event.getFullUrl() ) + ); + } + ); + } - return false; - } ); + return false; + } + ); // Return the first matched site if ( arrayLen( matchedSite ) ) { @@ -336,10 +318,12 @@ component /** * Get all sites for export */ - function getAllForExport(){ - return getAll().map( function( thisItem ){ - return thisItem.getMemento( profile: "export" ); - } ); + function getAllForExport() { + return getAll().map( + function( thisItem ) { + return thisItem.getMemento( profile = "export" ); + } + ); } /** @@ -352,14 +336,17 @@ component * * @throws InvalidImportFormat */ - string function importFromFile( required importFile, boolean override = false ){ - var data = fileRead( arguments.importFile ); + string function importFromFile( required importFile, boolean override = false ) { + var data = fileRead( arguments.importFile ); var importLog = createObject( "java", "java.lang.StringBuilder" ).init( - "Starting import with override = #arguments.override#...
      " - ); + "Starting import with override = #arguments.override#...
      " + ); if ( !isJSON( data ) ) { - throw( message: "Cannot import file as the contents is not JSON", type: "InvalidImportFormat" ); + throw( + message = "Cannot import file as the contents is not JSON", + type = "InvalidImportFormat" + ); } variables.logger.info( "Site import from file requested." ); @@ -385,38 +372,40 @@ component required any importData, boolean override = false, required any importLog - ){ + ) { // if struct, inflate into an array if ( isStruct( arguments.importData ) ) { - arguments.importData = [ arguments.importData ]; + arguments.importData = [ arguments.importData]; } - variables.logger.info( "+ Site import will try to import (#arrayLen( arguments.importData )#) sites." ); + variables.logger.info( + "+ Site import will try to import (#arrayLen( arguments.importData )#) sites." + ); transaction { // iterate and import for ( var thisSite in arguments.importData ) { - var oSite = this.findBySlug( slug: thisSite.slug ); - oSite = ( isNull( oSite ) ? new () : oSite ); + var oSite = this.findBySlug( slug = thisSite.slug ); + oSite = ( isNull( oSite ) ? new() : oSite ); // if new or persisted with override then save. if ( !oSite.isLoaded() ) { variables.logger.info( "+ New site will be imported: #thisSite.slug#" ); arguments.importLog.append( "New site will be imported: #thisSite.slug#
      " ); importSite( - site : oSite, - memento : thisSite, - importLog: arguments.importLog, - override : arguments.override + site = oSite, + memento = thisSite, + importLog = arguments.importLog, + override = arguments.override ); - } else if ( oSite.isLoaded() and arguments.override ) { + } else if ( oSite.isLoaded() && arguments.override ) { variables.logger.info( "+ Overidding site: #thisSite.slug#" ); arguments.importLog.append( "Overriding site: #thisSite.slug#
      " ); importSite( - site : oSite, - memento : thisSite, - importLog: arguments.importLog, - override : arguments.override + site = oSite, + memento = thisSite, + importLog = arguments.importLog, + override = arguments.override ); } else { variables.logger.info( "!! Skipping persisted site: #thisSite.slug#" ); @@ -449,18 +438,18 @@ component required memento, required importLog, required override - ){ + ) { // Setup logging function - var logThis = function( message ){ + var logThis = function( message ) { variables.logger.info( arguments.message ); importLog.append( arguments.message & "
      " ); }; transaction { // Aliases - var oSite = arguments.site; - var siteData = arguments.memento; - var populator = getBeanPopulator(); + var oSite = arguments.site; + var siteData = arguments.memento; + var populator = getBeanPopulator(); // populate content from data and ignore relationships, we need to build those manually. var excludedFields = [ "categories", @@ -472,11 +461,11 @@ component "settings" ]; populator.populateFromStruct( - target = oSite, - memento = siteData, - exclude = arrayToList( excludedFields ), - composeRelationships = false - ); + target = oSite, + memento = siteData, + exclude = arrayToList( excludedFields ), + composeRelationships = false + ); // Import Settings if ( oSite.isLoaded() ) { @@ -484,98 +473,111 @@ component // If persisted, do cleanups // If on Adobe, run hard deletes due to Hibernate issue with cascade on integration tests. if ( !server.keyExists( "lucee" ) ) { - variables.settingService.deleteWhere( site: oSite ); + variables.settingService.deleteWhere( site = oSite ); } oSite.removeAllSettings(); } oSite.setSettings( - siteData.settings.map( function( thisSetting ){ - // Avoid the boolean casting to string of hell!! - arguments.thisSetting.value = toString( arguments.thisSetting.value ); - logThis( "+ Importing setting: (#thisSetting.name#) to site #oSite.getSlug()#" ); - return populator - .populateFromStruct( - target = variables.settingService.new(), - memento = thisSetting, - exclude = "site", - composeRelationships = false + siteData.settings.map( + function( thisSetting ) { + arguments.thisSetting.value = toString( arguments.thisSetting.value ); + logThis( + "+ Importing setting: (#thisSetting.name#) to site #oSite.getSlug()#" + ); + return populator.populateFromStruct( + target = variables.settingService.new(), + memento = thisSetting, + exclude = "site", + composeRelationships = false + ).setSite( oSite ); + } ) - .setSite( oSite ); - } ) - ); + ); logThis( "+ Site settings for #oSite.getSlug()# imported." ); // IMPORT CATEGORIES if ( arrayLen( siteData.categories ) ) { oSite.setCategories( - siteData.categories.map( function( thisCategory ){ - logThis( "+ Importing category: (#thisCategory.slug#) to site #oSite.getSlug()#" ); - if ( oSite.isLoaded() ) { - return variables.categoryService.getOrCreateBySlug( - category: thisCategory.slug, - site : oSite - ); - } - return variables.categoryService.new( { - category : arguments.thisCategory.category, - slug : arguments.thisCategory.slug, - site : oSite - } ); - } ) - ); + siteData.categories.map( + function( thisCategory ) { + logThis( + "+ Importing category: (#thisCategory.slug#) to site #oSite.getSlug()#" + ); + if ( oSite.isLoaded() ) { + return variables.categoryService.getOrCreateBySlug( category = thisCategory.slug, + site = oSite ); + } + return variables.categoryService.new( + { + category: arguments.thisCategory.category, + slug : arguments.thisCategory.slug, + site : oSite + } + ); + } + ) + ); logThis( "+ Site categories for #oSite.getSlug()# imported." ); } // Note it for persistence so we can do the rest of the relationships this.save( oSite ); - logThis( "+ Site (#oSite.getSlug()#) saved to session, starting to import content now..." ); + logThis( + "+ Site (#oSite.getSlug()#) saved to session, starting to import content now..." + ); // IMPORT MENUS if ( arrayLen( siteData.menus ) ) { - logThis( "+ Importing menus (#arrayLen( siteData.menus )#) to site #arguments.site.getSlug()#" ); - getWireBox() - .getInstance( "menuService@contentbox" ) - .importFromData( - importData: siteData.menus, - override : arguments.override, - importLog : arguments.importLog, - site : oSite + logThis( + "+ Importing menus (#arrayLen( siteData.menus )#) to site #arguments.site.getSlug()#" + ); + getWireBox().getInstance( "menuService@contentbox" ).importFromData( + importData = siteData.menus, + override = arguments.override, + importLog = arguments.importLog, + site = oSite ); - logThis( "+ Imported (#arrayLen( siteData.menus )#) menus to site #arguments.site.getSlug()#" ); + logThis( + "+ Imported (#arrayLen( siteData.menus )#) menus to site #arguments.site.getSlug()#" + ); } else { logThis( "!! No menus found on import data, skipping..." ); } // IMPORT ENTRIES if ( arrayLen( siteData.entries ) ) { - logThis( "+ Importing entries (#arrayLen( siteData.entries )#) to site #arguments.site.getSlug()#" ); - getWireBox() - .getInstance( "entryService@contentbox" ) - .importFromData( - importData: siteData.entries, - override : arguments.override, - importLog : arguments.importLog, - site : oSite + logThis( + "+ Importing entries (#arrayLen( siteData.entries )#) to site #arguments.site.getSlug()#" + ); + getWireBox().getInstance( "entryService@contentbox" ).importFromData( + importData = siteData.entries, + override = arguments.override, + importLog = arguments.importLog, + site = oSite ); - logThis( "+ Imported (#arrayLen( siteData.entries )#) entries to site #arguments.site.getSlug()#" ); + logThis( + "+ Imported (#arrayLen( siteData.entries )#) entries to site #arguments.site.getSlug()#" + ); } else { logThis( "!! No entries found on import data, skipping..." ); } // IMPORT PAGES if ( arrayLen( siteData.pages ) ) { - logThis( "+ Importing pages (#arrayLen( siteData.pages )#) to site #arguments.site.getSlug()#" ); - getWireBox() - .getInstance( "pageService@contentbox" ) - .importFromData( - importData: siteData.pages, - override : arguments.override, - importLog : arguments.importLog, - site : oSite + logThis( + "+ Importing pages (#arrayLen( siteData.pages )#) to site #arguments.site.getSlug()#" + ); + getWireBox().getInstance( "pageService@contentbox" ).importFromData( + importData = siteData.pages, + override = arguments.override, + importLog = arguments.importLog, + site = oSite ); - logThis( "+ Imported (#arrayLen( siteData.pages )#) pages to site #arguments.site.getSlug()#" ); + logThis( + "+ Imported (#arrayLen( siteData.pages )#) pages to site #arguments.site.getSlug()#" + ); } else { logThis( "!! No pages found on import data, skipping..." ); } @@ -585,13 +587,11 @@ component logThis( "+ Importing contentStore (#arrayLen( siteData.contentStore )#) to site #arguments.site.getSlug()#" ); - getWireBox() - .getInstance( "contentStoreService@contentbox" ) - .importFromData( - importData: siteData.contentStore, - override : arguments.override, - importLog : arguments.importLog, - site : oSite + getWireBox().getInstance( "contentStoreService@contentbox" ).importFromData( + importData = siteData.contentStore, + override = arguments.override, + importLog = arguments.importLog, + site = oSite ); logThis( @@ -601,7 +601,52 @@ component logThis( "!! No contentStore found on import data, skipping..." ); } } + + // end site transaction } -} + /** + * Save operation called by the transactional `save()` method + * Due to transactional issues on Lucee + */ + private function _save( required site ) { + // Create all site settings if this is a new site + if ( !arguments.site.isLoaded() ) { + arguments.site.setSettings( + variables + .settingService + .getSiteSettingDefaults() + .reduce( + ( result, setting, value ) => { + arguments.result.append( + variables.settingService.new( + { + name : arguments.setting, + value : trim( arguments.value ), + isCore: true, + site : site + } + ) + ) + return arguments.result + }, + [] + ) + ) + } + + // Persist the site + super.save( arguments.site ) + + // Activate the site's theme + variables.themeService.startupTheme( + name = arguments.site.getActiveTheme(), + site = arguments.site + ) + + // Create media root folder for the site + ensureSiteMediaFolder( arguments.site ) + } + +} \ No newline at end of file diff --git a/modules/contentbox/models/ui/AdminMenuService.cfc b/modules/contentbox/models/ui/AdminMenuService.cfc index c14e8d201f..4e29a24152 100755 --- a/modules/contentbox/models/ui/AdminMenuService.cfc +++ b/modules/contentbox/models/ui/AdminMenuService.cfc @@ -6,59 +6,61 @@ * Manages the admin menu services for the header and top menu */ component accessors="true" threadSafe singleton { - /** * This holds the top menu structure */ property name="topMenu" type="array"; + /** * This is a reference map of the topMenu array */ property name="topMenuMap" type="struct"; + /** * This holds the header menu structure */ property name="headerMenu" type="array"; + /** * This holds the support menu structure */ property name="supportMenu" type="array"; + /** * This holds the utils menu structure */ property name="utilsMenu" type="array"; + /** * This holds the profile menu structure */ property name="profileMenu" type="array"; + /** * This is a reference map of the headerMenu array */ property name="headerMenuMap" type="struct"; + /** * Injected Avatar */ - property - name ="avatar" - type ="any" - inject="Avatar@contentbox"; + property name="avatar" type="any" inject="Avatar@contentbox"; // DI property name="log" inject="logbox:logger:{this}"; - // Top Menu Slugs - this.DASHBOARD = "dashboard"; - this.CONTENT = "content"; - this.COMMENTS = "comments"; - this.LOOK_FEEL = "lookAndFeel"; - this.MODULES = "modules"; - this.USERS = "users"; - this.TOOLS = "tools"; - this.SYSTEM = "system"; + this.DASHBOARD = "dashboard"; + this.CONTENT = "content"; + this.COMMENTS = "comments"; + this.LOOK_FEEL = "lookAndFeel"; + this.MODULES = "modules"; + this.USERS = "users"; + this.TOOLS = "tools"; + this.SYSTEM = "system"; this.ADMIN_ENTRYPOINT = ""; // Header Menu Slugs - this.HEADER_ABOUT = "about"; + this.HEADER_ABOUT = "about"; this.HEADER_PROFILE = "profile"; /** @@ -69,33 +71,33 @@ component accessors="true" threadSafe singleton { * @coldbox ColdBox Handler * @coldbox.inject coldbox */ - AdminMenuService function init( required requestService, required coldbox ){ + AdminMenuService function init( required requestService, required coldbox ) { // init menu array - variables.topMenu = []; + variables.topMenu = []; // init top menu structure holders - variables.topMenuMap = {}; + variables.topMenuMap = {}; // init header menu array - variables.headerMenu = []; + variables.headerMenu = []; // init header menu array - variables.supportMenu = []; + variables.supportMenu = []; // init header menu array - variables.utilsMenu = []; + variables.utilsMenu = []; // init header menu array - variables.profileMenu = []; + variables.profileMenu = []; // init profile menu structure - variables.headerMenuMap = {}; + variables.headerMenuMap = {}; // top menu pointer - variables.thisTopMenu = ""; + variables.thisTopMenu = ""; // header menu pointer variables.thisHeaderMenu = ""; // store request service variables.requestService = arguments.requestService; // store coldbox - variables.coldbox = arguments.coldbox; + variables.coldbox = arguments.coldbox; // Store admin entry point - this.ADMIN_ENTRYPOINT = arguments.coldbox.getSetting( "modules" )[ "contentbox-admin" ].entryPoint; + this.ADMIN_ENTRYPOINT = arguments.coldbox.getSetting( "modules" )[ "contentbox-admin" ].entryPoint; // store module info - variables.moduleConfig = arguments.coldbox.getSetting( "modules" )[ "contentbox" ]; + variables.moduleConfig = arguments.coldbox.getSetting( "modules" )[ "contentbox" ]; // create default menus createHeaderMenu(); createDefaultMenu(); @@ -108,13 +110,17 @@ component accessors="true" threadSafe singleton { * @event The event context * @menu The menu struct */ - function buildLIAttributes( required any event, required any menu ){ - var attributes = { "class" : "#menu.class#", "data-name" : "#menu.name#" }; + function buildLIAttributes( required any event, required any menu ) { + var attributes = { "class": "#menu.class#", "data-name": "#menu.name#" }; if ( structKeyExists( menu, "id" ) && len( menu.id ) ) { attributes[ "id" ] = menu.id; } if ( event.getPrivateValue( name = "tab#menu.name#", defaultValue = false ) ) { - listAppend( attributes.class, "active", " " ); + listAppend( + attributes.class, + "active", + " " + ); } return createAttributeList( attributes ); } @@ -130,8 +136,8 @@ component accessors="true" threadSafe singleton { required any event, required any menu, structDefaults = {} - ){ - var attributes = { "class" : structKeyExists( structDefaults, "class" ) ? structDefaults.class : "" }; + ) { + var attributes = { "class": structKeyExists( structDefaults, "class" ) ? structDefaults.class : "" }; if ( len( arguments.menu.itemClass ) ) { attributes.class &= " #arguments.menu.itemClass#"; @@ -182,7 +188,7 @@ component accessors="true" threadSafe singleton { * * @attributes The struct of attributes to build the list from */ - function createAttributeList( required struct attributes ){ + function createAttributeList( required struct attributes ) { var attributeList = ""; for ( var key in arguments.attributes ) { attributeList &= "#key#=""#attributes[ key ]#"""; @@ -193,13 +199,13 @@ component accessors="true" threadSafe singleton { /** * Create the default ContentBox header menu contributions */ - AdminMenuService function createHeaderMenu(){ + AdminMenuService function createHeaderMenu() { var event = requestService.getContext(); // Exit Handlers - var xehMyProfile = "#this.ADMIN_ENTRYPOINT#.authors.myprofile"; - var xehDoLogout = "#this.ADMIN_ENTRYPOINT#.security.doLogout"; - var xehAbout = "#this.ADMIN_ENTRYPOINT#.dashboard.about"; + var xehMyProfile = "#this.ADMIN_ENTRYPOINT#.authors.myprofile"; + var xehDoLogout = "#this.ADMIN_ENTRYPOINT#.security.doLogout"; + var xehAbout = "#this.ADMIN_ENTRYPOINT#.dashboard.about"; var xehAdminAction = "#this.ADMIN_ENTRYPOINT#.dashboard.reload"; // Register Profile Menu @@ -214,15 +220,14 @@ component accessors="true" threadSafe singleton { label = " My Profile", href = variables.buildLink, href_to = xehMyProfile, - data = { keybinding : "ctrl+shift+a" } - ) - .addHeaderSubMenu( + data = { keybinding: "ctrl+shift+a" } + ).addHeaderSubMenu( name = "logout", title = "ctrl+shift+L", label = " Logout", href = variables.buildLink, href_to = xehDoLogout, - data = { keybinding : "ctrl+shift+l" } + data = { keybinding: "ctrl+shift+l" } ); // Register modules reload menu @@ -233,13 +238,14 @@ component accessors="true" threadSafe singleton { itemType = "button", itemClass = "btn btn-more options toggle", permissions = "RELOAD_MODULES,RELOAD_CACHES", - data = { placement : "right" }, + data = { placement: "right" }, title = "Admin Actions" - ).addHeaderSubMenu( + ) + .addHeaderSubMenu( name = "rsscache", label = "Clear RSS Caches", permissions = "RELOAD_CACHES", - href = function( required menu, required event ){ + href = function( required menu, required event ) { return "javascript:adminAction( 'rss-purge', '#arguments.event.buildLink( xehAdminAction )#' )"; } ) @@ -247,7 +253,7 @@ component accessors="true" threadSafe singleton { name = "contentpurge", label = "Clear Content Caches", permissions = "RELOAD_CACHES", - href = function( required menu, required event ){ + href = function( required menu, required event ) { return "javascript:adminAction( 'content-purge', '#arguments.event.buildLink( xehAdminAction )#' )"; } ) @@ -255,7 +261,7 @@ component accessors="true" threadSafe singleton { name = "cachepurge", label = "Clear Template Cache", permissions = "RELOAD_CACHES", - href = function( required menu, required event ){ + href = function( required menu, required event ) { return "javascript:adminAction( 'cache-purge', '#arguments.event.buildLink( xehAdminAction )#' )"; } ) @@ -263,7 +269,7 @@ component accessors="true" threadSafe singleton { name = "app", label = "Reload Application", permissions = "RELOAD_MODULES", - href = function( required menu, required event ){ + href = function( required menu, required event ) { return "javascript:adminAction( 'app', '#arguments.event.buildLink( xehAdminAction )#' )"; } ) @@ -271,11 +277,11 @@ component accessors="true" threadSafe singleton { name = "orm", label = "Reload ORM", permissions = "RELOAD_MODULES", - href = function( required menu, required event ){ + href = function( required menu, required event ) { return "javascript:adminAction( 'orm', '#arguments.event.buildLink( xehAdminAction )#' )"; } - ) - ; + ); + return this; } @@ -286,7 +292,7 @@ component accessors="true" threadSafe singleton { * @menu The menu info * @event The request context */ - function buildLink( required menu, required event ){ + function buildLink( required menu, required event ) { // Normal a links if ( structKeyExists( arguments.menu, "href_to" ) ) { return arguments.event.buildLink( arguments.menu.href_to ); @@ -299,17 +305,17 @@ component accessors="true" threadSafe singleton { /** * Dynamic menu label */ - function buildProfileLabel(){ + function buildProfileLabel() { var event = requestService.getContext(); - var prc = event.getCollection( private = true ); + var prc = event.getCollection( private = true ); savecontent variable="profileLabel" { writeOutput( variables.avatar.renderAvatar( - email = prc.oCurrentAuthor.getEmail(), - size = "35", - class = "img-circle" - ) + email = prc.oCurrentAuthor.getEmail(), + size = "35", + class = "img-circle" + ) ); writeOutput( "" ); } @@ -320,45 +326,45 @@ component accessors="true" threadSafe singleton { /** * Create the default ContentBox menu */ - AdminMenuService function createDefaultMenu(){ + AdminMenuService function createDefaultMenu() { var event = requestService.getContext(); - var prc = {}; + var prc = {}; // Global Admin Exit Handlers prc.xehDashboard = "#this.ADMIN_ENTRYPOINT#.dashboard"; // Entries Tab - prc.xehEntries = "#this.ADMIN_ENTRYPOINT#.entries"; + prc.xehEntries = "#this.ADMIN_ENTRYPOINT#.entries"; prc.xehEntriesEditor = "#this.ADMIN_ENTRYPOINT#.entries.editor"; - prc.xehCategories = "#this.ADMIN_ENTRYPOINT#.categories"; - prc.xehTemplates = "#this.ADMIN_ENTRYPOINT#.contentTemplates"; + prc.xehCategories = "#this.ADMIN_ENTRYPOINT#.categories"; + prc.xehTemplates = "#this.ADMIN_ENTRYPOINT#.contentTemplates"; // Content Tab - prc.xehPages = "#this.ADMIN_ENTRYPOINT#.pages"; - prc.xehPagesEditor = "#this.ADMIN_ENTRYPOINT#.pages.editor"; + prc.xehPages = "#this.ADMIN_ENTRYPOINT#.pages"; + prc.xehPagesEditor = "#this.ADMIN_ENTRYPOINT#.pages.editor"; prc.xehContentStore = "#this.ADMIN_ENTRYPOINT#.contentstore"; prc.xehMediaManager = "#this.ADMIN_ENTRYPOINT#.mediamanager"; - prc.xehMenuManager = "#this.ADMIN_ENTRYPOINT#.menus"; + prc.xehMenuManager = "#this.ADMIN_ENTRYPOINT#.menus"; // Comments Tab - prc.xehComments = "#this.ADMIN_ENTRYPOINT#.comments"; + prc.xehComments = "#this.ADMIN_ENTRYPOINT#.comments"; prc.xehCommentsettings = "#this.ADMIN_ENTRYPOINT#.comments.settings"; - prc.xehSubscribers = "#this.ADMIN_ENTRYPOINT#.subscribers"; + prc.xehSubscribers = "#this.ADMIN_ENTRYPOINT#.subscribers"; // Look and Feel Tab - prc.xehThemes = "#this.ADMIN_ENTRYPOINT#.themes"; + prc.xehThemes = "#this.ADMIN_ENTRYPOINT#.themes"; prc.xehactiveTheme = "#this.ADMIN_ENTRYPOINT#.themes.active"; - prc.xehWidgets = "#this.ADMIN_ENTRYPOINT#.widgets"; - prc.xehGlobalHTML = "#this.ADMIN_ENTRYPOINT#.globalHTML"; + prc.xehWidgets = "#this.ADMIN_ENTRYPOINT#.widgets"; + prc.xehGlobalHTML = "#this.ADMIN_ENTRYPOINT#.globalHTML"; // Modules prc.xehModules = "#this.ADMIN_ENTRYPOINT#.modules"; // Authors Tab - prc.xehAuthors = "#this.ADMIN_ENTRYPOINT#.authors"; - prc.xehAuthorEditor = "#this.ADMIN_ENTRYPOINT#.authors.editor"; - prc.xehPermissions = "#this.ADMIN_ENTRYPOINT#.permissions"; - prc.xehRoles = "#this.ADMIN_ENTRYPOINT#.roles"; + prc.xehAuthors = "#this.ADMIN_ENTRYPOINT#.authors"; + prc.xehAuthorEditor = "#this.ADMIN_ENTRYPOINT#.authors.editor"; + prc.xehPermissions = "#this.ADMIN_ENTRYPOINT#.permissions"; + prc.xehRoles = "#this.ADMIN_ENTRYPOINT#.roles"; prc.xehPermissionGroups = "#this.ADMIN_ENTRYPOINT#.permissionGroups"; // Tools @@ -366,12 +372,12 @@ component accessors="true" threadSafe singleton { prc.xehToolsExport = "#this.ADMIN_ENTRYPOINT#.tools.exporter"; // System - prc.xehSettings = "#this.ADMIN_ENTRYPOINT#.settings"; - prc.xehSitesManager = "#this.ADMIN_ENTRYPOINT#.sites"; + prc.xehSettings = "#this.ADMIN_ENTRYPOINT#.settings"; + prc.xehSitesManager = "#this.ADMIN_ENTRYPOINT#.sites"; prc.xehSecurityRules = "#this.ADMIN_ENTRYPOINT#.securityrules"; - prc.xehRawSettings = "#this.ADMIN_ENTRYPOINT#.settings.raw"; - prc.xehAuthLogs = "#this.ADMIN_ENTRYPOINT#.settings.authLogs"; - prc.xehAbout = "#this.ADMIN_ENTRYPOINT#.about"; + prc.xehRawSettings = "#this.ADMIN_ENTRYPOINT#.settings.raw"; + prc.xehAuthLogs = "#this.ADMIN_ENTRYPOINT#.settings.authLogs"; + prc.xehAbout = "#this.ADMIN_ENTRYPOINT#.about"; // Dashboard addTopMenu( @@ -382,7 +388,10 @@ component accessors="true" threadSafe singleton { ); // Content - addTopMenu( name = this.CONTENT, label = " Content" ) + addTopMenu( + name = this.CONTENT, + label = " Content" + ) .addSubMenu( name = "Pages", label = "Sitemap", @@ -435,7 +444,10 @@ component accessors="true" threadSafe singleton { ); // Comments - addTopMenu( name = this.COMMENTS, label = " Comments" ) + addTopMenu( + name = this.COMMENTS, + label = " Comments" + ) .addSubMenu( name = "Inbox", label = "Inbox", @@ -459,7 +471,10 @@ component accessors="true" threadSafe singleton { ); // Look and Feel - addTopMenu( name = this.LOOK_FEEL, label = " Look & Feel" ) + addTopMenu( + name = this.LOOK_FEEL, + label = " Look & Feel" + ) .addSubMenu( name = "activetheme", label = "Active Theme", @@ -495,11 +510,11 @@ component accessors="true" threadSafe singleton { label = " Modules", permissions = "MODULES_ADMIN" ).addSubMenu( - name = "Manage", - label = "Manage", - href = variables.buildLink, - href_to = prc.xehModules - ); + name = "Manage", + label = "Manage", + href = variables.buildLink, + href_to = prc.xehModules + ); // User addTopMenu( name = this.USERS, label = " Users" ) @@ -533,15 +548,16 @@ component accessors="true" threadSafe singleton { ); // Tools - addTopMenu( name = this.TOOLS, label = " Tools" ) - .addSubMenu( + addTopMenu( + name = this.TOOLS, + label = " Tools" + ).addSubMenu( name = "Import", label = "Import", href = variables.buildLink, href_to = prc.xehToolsImport, permissions = "TOOLS_IMPORT" - ) - .addSubMenu( + ).addSubMenu( name = "Export", label = "Export", href = variables.buildLink, @@ -554,7 +570,8 @@ component accessors="true" threadSafe singleton { name = this.SYSTEM, label = " System", permissions = "SYSTEM_TAB" - ).addSubMenu( + ) + .addSubMenu( name = "AuthLogs", label = "Auth Logs", href = variables.buildLink, @@ -581,7 +598,7 @@ component accessors="true" threadSafe singleton { label = "Settings", href = variables.buildLink, href_to = prc.xehSettings, - data = { "keybinding" : "ctrl+shift+c" } + data = { "keybinding": "ctrl+shift+c" } ) .addSubMenu( name = "SecurityRules", @@ -613,23 +630,23 @@ component accessors="true" threadSafe singleton { required string to, queryString = "", boolean ssl = false - ){ + ) { var event = requestService.getContext(); // Remove by 6.x if ( !isNull( arguments.linkTo ) ) { arguments.to = arguments.linkTo; } return event.buildLink( - to = "#this.ADMIN_ENTRYPOINT#.module.#arguments.module#.#arguments.to#", - queryString = arguments.queryString, - ssl = arguments.ssl - ); + to = "#this.ADMIN_ENTRYPOINT#.module.#arguments.module#.#arguments.to#", + queryString = arguments.queryString, + ssl = arguments.ssl + ); } /** * @name The name of the top menu */ - AdminMenuService function withTopMenu( required name ){ + AdminMenuService function withTopMenu( required name ) { thisTopMenu = arguments.name; return this; } @@ -639,7 +656,7 @@ component accessors="true" threadSafe singleton { * * @name The name of the header menu */ - AdminMenuService function withHeaderMenu( required name ){ + AdminMenuService function withHeaderMenu( required name ) { thisHeaderMenu = arguments.name; return this; } @@ -673,11 +690,11 @@ component accessors="true" threadSafe singleton { itemType = "a", itemClass = "", itemId = "" - ){ + ) { // stash pointer - variables.thisTopMenu = arguments.name; + variables.thisTopMenu = arguments.name; // store new top menu in reference map - variables.topMenuMap[ arguments.name ] = { submenu : [] }; + variables.topMenuMap[ arguments.name ] = { submenu: [] }; structAppend( variables.topMenuMap[ arguments.name ], arguments, @@ -718,11 +735,11 @@ component accessors="true" threadSafe singleton { itemType = "a", itemClass = "", itemId = "" - ){ + ) { // stash pointer - variables.thisHeaderMenu = arguments.name; + variables.thisHeaderMenu = arguments.name; // store new top menu in reference map - variables.headerMenuMap[ arguments.name ] = { submenu : [] }; + variables.headerMenuMap[ arguments.name ] = { submenu: [] }; structAppend( variables.headerMenuMap[ arguments.name ], @@ -766,20 +783,22 @@ component accessors="true" threadSafe singleton { itemType = "a", itemClass = "", itemId = "" - ){ + ) { // Check if thisTopMenu set? - if ( !len( thisTopMenu ) AND !structKeyExists( arguments, "topMenu" ) ) { + if ( !len( thisTopMenu ) && !structKeyExists( arguments, "topMenu" ) ) { throw( "No top menu passed or concatenated with" ); } // check this pointer - if ( len( thisTopMenu ) AND !structKeyExists( arguments, "topMenu" ) ) { + if ( len( thisTopMenu ) && !structKeyExists( arguments, "topMenu" ) ) { arguments.topmenu = thisTopMenu; } // store in top menu if ( variables.topMenuMap.keyExists( arguments.topMenu ) ) { arrayAppend( variables.topMenuMap[ arguments.topMenu ].submenu, arguments ); } else { - log.warn( "requested top menu (#arguments.topMenu#) does not exist when calling addSubMenu()" ); + log.warn( + "requested top menu (#arguments.topMenu#) does not exist when calling addSubMenu()" + ); } // return return this; @@ -816,14 +835,14 @@ component accessors="true" threadSafe singleton { itemType = "a", itemClass = "", itemId = "" - ){ + ) { // Check if thisTopMenu set? - if ( !len( thisHeaderMenu ) AND !structKeyExists( arguments, "headerMenu" ) ) { + if ( !len( thisHeaderMenu ) && !structKeyExists( arguments, "headerMenu" ) ) { throw( "No header menu passed or concatenated with" ); } // check this pointer - if ( len( thisHeaderMenu ) AND !structKeyExists( arguments, "headerMenu" ) ) { + if ( len( thisHeaderMenu ) && !structKeyExists( arguments, "headerMenu" ) ) { arguments.headerMenu = thisHeaderMenu; } @@ -831,7 +850,9 @@ component accessors="true" threadSafe singleton { if ( headerMenuMap.keyExists( arguments.headerMenu ) ) { arrayAppend( headerMenuMap[ arguments.headerMenu ].submenu, arguments ); } else { - log.warn( "requested header menu (#arguments.headerMenu#) does not exist when calling addHeaderSubMenu()" ); + log.warn( + "requested header menu (#arguments.headerMenu#) does not exist when calling addHeaderSubMenu()" + ); } // return @@ -844,17 +865,17 @@ component accessors="true" threadSafe singleton { * @topMenu The optional top menu name to add this sub level menu to or if concatenated then it uses that one. * @name The unique name for this sub level menu */ - AdminMenuService function removeSubMenu( required topMenu, required name ){ + AdminMenuService function removeSubMenu( required topMenu, required name ) { // Verify top menu exists, else just return if ( !variables.topMenuMap.keyExists( arguments.topMenu ) ) { log.warn( - "Cannot remove submenu (#arguments.name#) as the top menu requested (#arguments.topMenu#) does not exist" - ); + "Cannot remove submenu (#arguments.name#) as the top menu requested (#arguments.topMenu#) does not exist" + ); return this; } - for ( var x = 1; x lte arrayLen( variables.topMenuMap[ arguments.topMenu ].subMenu ); x++ ) { - if ( variables.topMenuMap[ arguments.topMenu ].subMenu[ x ].name eq arguments.name ) { + for ( var x = 1; x LTE arrayLen( variables.topMenuMap[ arguments.topMenu ].subMenu ); x++ ) { + if ( variables.topMenuMap[ arguments.topMenu ].subMenu[ x ].name EQ arguments.name ) { arrayDeleteAt( variables.topMenuMap[ arguments.topMenu ].subMenu, x ); break; } @@ -870,17 +891,17 @@ component accessors="true" threadSafe singleton { * @headerMenu The optional header menu name to remove from * @name The sub menu to remove */ - AdminMenuService function removeHeaderSubMenu( required headerMenu, required name ){ + AdminMenuService function removeHeaderSubMenu( required headerMenu, required name ) { // Verify top menu exists, else just return if ( !variables.headerMenuMap.keyExists( arguments.headerMenu ) ) { log.warn( - "Cannot remove submenu (#arguments.name#) as the header menu requested (#arguments.headerMenu#) does not exist" - ); + "Cannot remove submenu (#arguments.name#) as the header menu requested (#arguments.headerMenu#) does not exist" + ); return this; } - for ( var x = 1; x lte arrayLen( variables.headerMenuMap[ arguments.headerMenu ].subMenu ); x++ ) { - if ( variables.headerMenuMap[ arguments.headerMenu ].subMenu[ x ].name eq arguments.name ) { + for ( var x = 1; x LTE arrayLen( variables.headerMenuMap[ arguments.headerMenu ].subMenu ); x++ ) { + if ( variables.headerMenuMap[ arguments.headerMenu ].subMenu[ x ].name EQ arguments.name ) { arrayDeleteAt( variables.headerMenuMap[ arguments.headerMenu ].subMenu, x ); break; } @@ -895,11 +916,11 @@ component accessors="true" threadSafe singleton { * * @topMenu The optional top menu name to add this sub level menu to or if concatenated then it uses that one. */ - AdminMenuService function removeTopMenu( required topMenu ){ + AdminMenuService function removeTopMenu( required topMenu ) { var found = false; - for ( var x = 1; x lte arrayLen( variables.topMenu ); x++ ) { - if ( variables.topMenu[ x ].name eq arguments.topMenu ) { + for ( var x = 1; x LTE arrayLen( variables.topMenu ); x++ ) { + if ( variables.topMenu[ x ].name EQ arguments.topMenu ) { found = true; arrayDeleteAt( variables.topMenu, x ); structDelete( variables.topMenuMap, arguments.topMenu ); @@ -908,7 +929,9 @@ component accessors="true" threadSafe singleton { } if ( !found ) { - log.warn( "Top menu: #arguments.topMenu# not found when calling removeTopMenu" ); + log.warn( + "Top menu: #arguments.topMenu# not found when calling removeTopMenu" + ); } // return @@ -920,11 +943,11 @@ component accessors="true" threadSafe singleton { * * @headerMenu The header menu unique name to remove */ - AdminMenuService function removeHeaderMenu( required headerMenu ){ + AdminMenuService function removeHeaderMenu( required headerMenu ) { var found = false; - for ( var x = 1; x lte arrayLen( variables.headerMenu ); x++ ) { - if ( variables.headerMenu[ x ].name eq arguments.headerMenu ) { + for ( var x = 1; x LTE arrayLen( variables.headerMenu ); x++ ) { + if ( variables.headerMenu[ x ].name EQ arguments.headerMenu ) { found = true; arrayDeleteAt( variables.headerMenu, x ); structDelete( variables.headerMenuMap, arguments.headerMenu ); @@ -933,7 +956,9 @@ component accessors="true" threadSafe singleton { } if ( !found ) { - log.warn( "Header menu: #arguments.headerMenu# not found when calling removeHeaderMenu" ); + log.warn( + "Header menu: #arguments.headerMenu# not found when calling removeHeaderMenu" + ); } // return @@ -941,12 +966,12 @@ component accessors="true" threadSafe singleton { } /** - * Generate main top admin menu navigation bar + * Generate main top admin menu navigation bar */ - any function generateMenu(){ - var event = requestService.getContext(); - var prc = event.getCollection( private = true ); - var genMenu = ""; + any function generateMenu() { + var event = requestService.getContext(); + var prc = event.getCollection( private = true ); + var genMenu = ""; var thisMenu = variables.topMenu; savecontent variable="genMenu" { @@ -960,10 +985,10 @@ component accessors="true" threadSafe singleton { /** * Generate the header menu */ - any function generateHeaderMenu(){ - var event = requestService.getContext(); - var prc = event.getCollection( private = true ); - var genMenu = ""; + any function generateHeaderMenu() { + var event = requestService.getContext(); + var prc = event.getCollection( private = true ); + var genMenu = ""; var thisMenu = variables.headerMenu; savecontent variable="genMenu" { @@ -977,10 +1002,10 @@ component accessors="true" threadSafe singleton { /** * Generate the utility menu */ - any function generateUtilsMenu(){ - var event = requestService.getContext(); - var prc = event.getCollection( private = true ); - var genMenu = ""; + any function generateUtilsMenu() { + var event = requestService.getContext(); + var prc = event.getCollection( private = true ); + var genMenu = ""; var thisMenu = variables.headerMenuMap[ "utils" ]; savecontent variable="genMenu" { @@ -994,10 +1019,10 @@ component accessors="true" threadSafe singleton { /** * Generate dynamic profile menu */ - any function generateProfileMenu(){ - var event = requestService.getContext(); - var prc = event.getCollection( private = true ); - var genMenu = ""; + any function generateProfileMenu() { + var event = requestService.getContext(); + var prc = event.getCollection( private = true ); + var genMenu = ""; var thisMenu = variables.headerMenuMap[ "profile" ]; savecontent variable="genMenu" { @@ -1013,7 +1038,7 @@ component accessors="true" threadSafe singleton { * * @data The data struct */ - string function parseADataAttributes( required struct data ){ + string function parseADataAttributes( required struct data ) { var dataString = ""; for ( var dataKey in arguments.data ) { @@ -1025,4 +1050,4 @@ component accessors="true" threadSafe singleton { return dataString; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/ui/Avatar.cfc b/modules/contentbox/models/ui/Avatar.cfc index 37aa0c8829..31c26b77a5 100755 --- a/modules/contentbox/models/ui/Avatar.cfc +++ b/modules/contentbox/models/ui/Avatar.cfc @@ -1,16 +1,16 @@ -/* +/* * An avatar model object for ContentBox */ component singleton { - // DI property name="requestService" inject="coldbox:requestService"; + property name="requestStorage" inject="requestStorage@cbStorages"; /** * Constructor */ - function init(){ + function init() { return this; } @@ -24,7 +24,7 @@ component singleton { required email, numeric size = 80, rating = "PG" - ){ + ) { return "//www.gravatar.com/avatar.php?gravatar_id=#lCase( hash( arguments.email ) )#&s=#arguments.size#&r=#rating#"; } @@ -39,29 +39,38 @@ component singleton { required email, numeric size = 80, string class = "gravatar" - ){ + ) { // check settings - var prc = variables.requestService.getContext().getPrivateCollection(); - if ( NOT prc.cbSettings.cb_gravatar_display ) { + var prc = variables + .requestService + .getContext() + .getPrivateCollection(); + if ( !prc.cbSettings.cb_gravatar_display ) { return ""; } // Build out avatar - return variables.requestStorage.getOrSet( "avatar-#hash( arguments.toString() )#", function(){ - // render it out - savecontent variable="local.avatar" { - writeOutput( - " + return variables.requestStorage.getOrSet( + "avatar-#hash( arguments.toString() )#", + function() { + savecontent variable="local.avatar" { + writeOutput( + " " - ); - } - return local.avatar; - } ); + ); + } + return local.avatar; + } + ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/ui/BaseWidget.cfc b/modules/contentbox/models/ui/BaseWidget.cfc index 93b3677422..3e527567ce 100644 --- a/modules/contentbox/models/ui/BaseWidget.cfc +++ b/modules/contentbox/models/ui/BaseWidget.cfc @@ -1,81 +1,70 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox * --- * This is the base class for contentbox widgets which gives them access to ContentBox and ColdBox. */ -component accessors="true" extends="coldbox.system.FrameworkSupertype" { - +component accessors="true" extends ="coldbox.system.FrameworkSupertype" { // Shared DI all widgets receive property name="siteService" inject="siteService@contentbox"; + property name="categoryService" inject="categoryService@contentbox"; + property name="entryService" inject="entryService@contentbox"; + property name="pageService" inject="pageService@contentbox"; + property name="contentService" inject="contentService@contentbox"; + property name="contentVersionService" inject="contentVersionService@contentbox"; + property name="authorService" inject="authorService@contentbox"; + property name="commentService" inject="commentService@contentbox"; + property name="contentStoreService" inject="contentStoreService@contentbox"; + property name="menuService" inject="menuService@contentbox"; + property name="cb" inject="CBHelper@contentbox"; + property name="securityService" inject="securityService@contentbox"; + property name="html" inject="HTMLHelper@coldbox"; + property name="controller" inject="coldbox"; + property name="log" inject="logbox:logger:{this}"; // Local Properties - property - name ="name" - type ="string" - default=""; - - property - name ="version" - type ="string" - default=""; - - property - name ="description" - type ="string" - default=""; - - property - name ="author" - type ="string" - default=""; - - property - name ="authorURL" - type ="string" - default=""; - - property - name ="forgeBoxSlug" - type ="string" - default=""; - - property - name ="category" - type ="string" - default=""; - - property - name ="icon" - type ="string" - default=""; + property name="name" type="string" default=""; + + property name="version" type="string" default=""; + + property name="description" type="string" default=""; + + property name="author" type="string" default=""; + + property name="authorURL" type="string" default=""; + + property name="forgeBoxSlug" type="string" default=""; + + property name="category" type="string" default=""; + + property name="icon" type="string" default=""; /** * Base Constructor */ - function init(){ - variables.name = ""; - variables.version = ""; + function init() { + variables.name = ""; + variables.version = ""; variables.description = ""; - variables.author = ""; - variables.authorURL = ""; - variables.category = ""; - variables.icon = ""; + variables.author = ""; + variables.authorURL = ""; + variables.category = ""; + variables.icon = ""; return this; } @@ -85,8 +74,11 @@ component accessors="true" extends="coldbox.system.FrameworkSupertype" { * * @throws BaseClassException */ - any function renderIt(){ - throw( message = "This is a base method that you must implement", type = "BaseClassException" ); + any function renderIt() { + throw( + message = "This is a base method that you must implement", + type = "BaseClassException" + ); } /** @@ -94,10 +86,10 @@ component accessors="true" extends="coldbox.system.FrameworkSupertype" { * * @return array */ - array function getPublicMethods(){ + array function getPublicMethods() { var publicMethods = []; - var meta = getMetadata( this ); - var method = ""; + var meta = getMetadata( this ); + var method = ""; for ( var i = 1; i <= arrayLen( meta.functions ); i++ ) { method = meta.functions[ i ]; @@ -108,9 +100,8 @@ component accessors="true" extends="coldbox.system.FrameworkSupertype" { // Add conditions if ( !listContains( "init,onMissingMethod", method.name ) ) { if ( - !structKeyExists( method, "access" ) || ( - structKeyExists( method, "access" ) && !listContains( "private,package", method.access ) - ) + !structKeyExists( method, "access" ) || + ( structKeyExists( method, "access" ) && !listContains( "private,package", method.access ) ) ) { arrayAppend( publicMethods, method ); } @@ -122,7 +113,7 @@ component accessors="true" extends="coldbox.system.FrameworkSupertype" { /** * Detect if we are in admin mode or in the UI, and retrieve the site accordingly */ - function getSite(){ + function getSite() { if ( findNoCase( variables.cb.adminRoot(), getRequestContext().getCurrentRoutedUrl() ) ) { return variables.siteService.getCurrentWorkingSite(); } @@ -130,4 +121,4 @@ component accessors="true" extends="coldbox.system.FrameworkSupertype" { return variables.cb.site(); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/ui/Paging.cfc b/modules/contentbox/models/ui/Paging.cfc index 9df7ab286a..4954a7f37b 100755 --- a/modules/contentbox/models/ui/Paging.cfc +++ b/modules/contentbox/models/ui/Paging.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -41,23 +41,24 @@ * @author Luis Majano */ component accessors="true" singleton threadsafe { - // DI property name="controller" inject="coldbox"; + property name="settingService" inject="settingService@contentbox"; // Properties property name="pagingMaxRows"; + property name="PagingBandGap"; /** * Constructor */ - function init(){ + function init() { return this; } - function onDIComplete(){ + function onDIComplete() { // Setup Paging Properties setPagingMaxRows( variables.settingService.getSetting( "cb_paging_maxrows" ) ); setPagingBandGap( variables.settingService.getSetting( "cb_paging_bandgap" ) ); @@ -71,15 +72,15 @@ component accessors="true" singleton threadsafe { * * @return struct of { startrow:numeric, maxrow:numeric } */ - struct function getBoundaries( numeric pagingMaxRows, numeric page ){ - var boundaries = { "startrow" : 1, "maxrow" : 0 }; - var event = getController().getRequestService().getContext(); - var maxRows = !isNull( arguments.pagingMaxRows ) ? arguments.pagingMaxRows : getPagingMaxRows(); + struct function getBoundaries( numeric pagingMaxRows, numeric page ) { + var boundaries = { "startrow": 1, "maxrow": 0 }; + var event = getController().getRequestService().getContext(); + var maxRows = !isNull( arguments.pagingMaxRows ) ? arguments.pagingMaxRows : getPagingMaxRows(); arguments.page = isNull( arguments.page ) ? event.getValue( "page", 1 ) : arguments.page; boundaries.startrow = ( arguments.page * maxrows - maxRows ) + 1; - boundaries.maxrow = boundaries.startrow + maxRows - 1; + boundaries.maxrow = boundaries.startrow + maxRows - 1; return boundaries; } @@ -99,24 +100,33 @@ component accessors="true" singleton threadsafe { numeric pagingMaxRows, boolean asList = false, numeric page - ){ - var event = variables.controller.getRequestService().getContext(); - var currentPage = isNull( arguments.page ) ? event.getValue( "page", 1 ) : arguments.page; + ) { + var event = variables + .controller + .getRequestService() + .getContext(); + var currentPage = isNull( arguments.page ) ? event.getValue( "page", 1 ) : arguments.page; var pagingTabsUI = ""; - var maxRows = !isNull( arguments.pagingMaxRows ) ? arguments.pagingMaxRows : getPagingMaxRows(); - var bandGap = getPagingBandGap(); - var theLink = arguments.link; - var pageFrom = 0; - var pageTo = 0; - var pageIndex = 0; + var maxRows = !isNull( arguments.pagingMaxRows ) ? arguments.pagingMaxRows : getPagingMaxRows(); + var bandGap = getPagingBandGap(); + var theLink = arguments.link; + var pageFrom = 0; + var pageTo = 0; + var pageIndex = 0; // Only page if records found if ( arguments.foundRows > 0 ) { // Calculate Total Pages var totalPages = ceiling( arguments.foundRows / maxRows ); - if ( currentPage gt totalPages ) { - variables.controller.relocate( url: replace( theLink, "@page@", totalPages ) ); + if ( currentPage GT totalPages ) { + variables.controller.relocate( + url = replace( + theLink, + "@page@", + totalPages + ) + ); } savecontent variable="pagingTabsUI" { @@ -127,4 +137,4 @@ component accessors="true" singleton threadsafe { return pagingTabsUI; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/ui/Paging.cfm b/modules/contentbox/models/ui/Paging.cfm index 92b958cf95..f489387921 100644 --- a/modules/contentbox/models/ui/Paging.cfm +++ b/modules/contentbox/models/ui/Paging.cfm @@ -1,60 +1,177 @@ -
      -
      - - - +
      +
      + + + -
      +
      +
      + + + + + + + + +
      + + + + + \ No newline at end of file diff --git a/modules/contentbox/models/ui/ThemeService.cfc b/modules/contentbox/models/ui/ThemeService.cfc index f4ed0332e9..11f67dcb55 100644 --- a/modules/contentbox/models/ui/ThemeService.cfc +++ b/modules/contentbox/models/ui/ThemeService.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -6,18 +6,26 @@ * Manages ContentBox themes */ component accessors="true" threadSafe singleton { - // DI property name="settingService" inject="settingService@contentbox"; + property name="siteService" inject="siteService@contentbox"; + // Provide this one in, due to chicken and the egg issues. property name="widgetService" inject="provider:widgetService@contentbox"; + property name="moduleSettings" inject="coldbox:setting:modules"; + property name="interceptorService" inject="coldbox:interceptorService"; + property name="log" inject="logbox:logger:{this}"; + property name="wirebox" inject="wirebox"; + property name="html" inject="HTMLHelper@coldbox"; + property name="cbHelper" inject="provider:CBHelper@contentbox"; + property name="moduleService" inject="coldbox:moduleService"; /** @@ -43,12 +51,12 @@ component accessors="true" threadSafe singleton { /** * Constructor */ - ThemeService function init(){ + ThemeService function init() { // init properties - variables.themeRegistry = {}; - variables.coreThemesPath = ""; + variables.themeRegistry = {}; + variables.coreThemesPath = ""; variables.customThemesPath = ""; - variables.widgetCache = {}; + variables.widgetCache = {}; return this; } @@ -56,9 +64,9 @@ component accessors="true" threadSafe singleton { /** * onDIComplete startup the theming services according to loaded module data */ - void function onDIComplete(){ + void function onDIComplete() { // setup location paths - variables.coreThemesPath = variables.moduleSettings[ "contentbox" ].path & "/themes"; + variables.coreThemesPath = variables.moduleSettings[ "contentbox" ].path & "/themes"; variables.customThemesPath = variables.moduleSettings[ "contentbox-custom" ].path & "/_themes"; // Register all themes @@ -68,18 +76,26 @@ component accessors="true" threadSafe singleton { /** * Does the current active theme have a maintenance view */ - boolean function themeMaintenanceViewExists(){ - return fileExists( expandPath( variables.CBHelper.themeRoot() & "/views/maintenance.cfm" ) ); + boolean function themeMaintenanceViewExists() { + return fileExists( + expandPath( variables.CBHelper.themeRoot() & "/views/maintenance.cfm" ) + ); } /** * Get the current active theme's maintenance layout */ - string function getThemeMaintenanceLayout(){ + string function getThemeMaintenanceLayout() { var layout = "pages"; // verify existence of convention - if ( fileExists( expandPath( variables.CBHelper.themeRoot() & "/layouts/maintenance.cfm" ) ) ) { + if ( + fileExists( + expandPath( + variables.CBHelper.themeRoot() & "/layouts/maintenance.cfm" + ) + ) + ) { layout = "maintenance"; } @@ -92,13 +108,19 @@ component accessors="true" threadSafe singleton { * @format export format * @layout layout name */ - string function getThemePrintLayout( required format, required layout ){ + string function getThemePrintLayout( required format, required layout ) { // some cleanup, just in case - arguments.layout = replaceNoCase( arguments.layout, ".cfm", "" ); + arguments.layout = replaceNoCase( + arguments.layout, + ".cfm", + "" + ); // verify existence of convention if ( fileExists( - expandPath( variables.CBHelper.themeRoot() & "/layouts/#arguments.layout#_#arguments.format#.cfm" ) + expandPath( + variables.CBHelper.themeRoot() & "/layouts/#arguments.layout#_#arguments.format#.cfm" + ) ) ) { return "#arguments.layout#_#arguments.format#"; @@ -110,11 +132,15 @@ component accessors="true" threadSafe singleton { /** * Get the current theme's search layout */ - string function getThemeSearchLayout(){ + string function getThemeSearchLayout() { var layout = "pages"; // verify existence of convention - if ( fileExists( expandPath( variables.CBHelper.themeRoot() & "/layouts/search.cfm" ) ) ) { + if ( + fileExists( + expandPath( variables.CBHelper.themeRoot() & "/layouts/search.cfm" ) + ) + ) { layout = "search"; } @@ -126,14 +152,21 @@ component accessors="true" threadSafe singleton { * * @widgetName The name of the widget */ - string function getThemeWidgetInvocationPath( required string widgetName ){ - var path = ""; - var parsedName = replaceNoCase( arguments.widgetName, "~", "", "one" ); + string function getThemeWidgetInvocationPath( required string widgetName ) { + var path = ""; + var parsedName = replaceNoCase( + arguments.widgetName, + "~", + "", + "one" + ); // if requested widget exists in the cache, return the path if ( structKeyExists( variables.widgetCache, parsedName ) ) { path = variables.widgetCache[ parsedName ].invocationPath; } else { - log.error( "Could not find '#parsedName#' widget in the currently active theme." ); + log.error( + "Could not find '#parsedName#' widget in the currently active theme." + ); } return path; } @@ -142,13 +175,16 @@ component accessors="true" threadSafe singleton { * This method is called from the UI module to make sure all site themes are online before * serving requets */ - function startupSiteThemes(){ + function startupSiteThemes() { // Startup the themes - variables.siteService + variables + .siteService .getAllSiteThemes() - .each( function( record ){ - startupTheme( name: arguments.record[ "activeTheme" ], site: arguments.record[ "siteID" ] ); - } ); + .each( + function( record ) { + startupTheme( name = arguments.record[ "activeTheme" ], site = arguments.record[ "siteID" ] ); + } + ); // Flush the settings now variables.settingService.flushSettingsCache(); @@ -165,10 +201,10 @@ component accessors="true" threadSafe singleton { required name, boolean processWidgets = true, any site = "" - ){ + ) { // Get theme record information var themeRecord = getThemeRecord( arguments.name ); - var oTheme = themeRecord.descriptor; + var oTheme = themeRecord.descriptor; // Determine object or id if ( isSimpleValue( arguments.site ) ) { arguments.site = variables.siteService.getOrFail( arguments.site ); @@ -176,37 +212,42 @@ component accessors="true" threadSafe singleton { // Register description as an interceptor with custom points variables.interceptorService.registerInterceptor( - interceptorObject: oTheme, - interceptorName : "cbtheme-#arguments.name#-#arguments.site.getsiteID()#", - customPoints : themeRecord.customInterceptionPoints - ); + interceptorObject = oTheme, + interceptorName = "cbtheme-#arguments.name#-#arguments.site.getsiteID()#", + customPoints = themeRecord.customInterceptionPoints + ); // Register theme settings? if ( structKeyExists( oTheme, "settings" ) ) { registerThemeSettings( - name : arguments.name, - settings: oTheme.settings, - site : arguments.site + name = arguments.name, + settings = oTheme.settings, + site = arguments.site ); } // build widget cache for active theme for ( var thisWidget in themeRecord.widgets.listToArray() ) { - var widgetName = replaceNoCase( thisWidget, ".cfc", "", "one" ); + var widgetName = replaceNoCase( + thisWidget, + ".cfc", + "", + "one" + ); variables.widgetCache[ widgetName ] = { - name : widgetName, - invocationPath : "#themeRecord.invocationPath#.widgets.#widgetName#", - path : "#themeRecord.path#/#arguments.name#/widgets/#thisWidget#", - theme : arguments.name + name : widgetName, + invocationPath: "#themeRecord.invocationPath#.widgets.#widgetName#", + path : "#themeRecord.path#/#arguments.name#/widgets/#thisWidget#", + theme : arguments.name }; } // activate theme modules for ( var thisModule in themeRecord.modules.listToArray() ) { variables.moduleService.registerAndActivateModule( - moduleName : thisModule, - invocationPath: "#themeRecord.invocationPath#.modules" - ); + moduleName = thisModule, + invocationPath = "#themeRecord.invocationPath#.modules" + ); } // Register all widgets @@ -216,13 +257,13 @@ component accessors="true" threadSafe singleton { // Announce theme activation variables.interceptorService.announce( - "cbadmin_onThemeActivation", - { - themeName : arguments.name, - themeRecord : themeRecord, - site : arguments.site - } - ); + "cbadmin_onThemeActivation", + { + themeName : arguments.name, + themeRecord: themeRecord, + site : arguments.site + } + ); // Call Theme Callbacks: onActivation if ( structKeyExists( oTheme, "onActivation" ) ) { @@ -239,27 +280,32 @@ component accessors="true" threadSafe singleton { * * @return ThemeService */ - function saveThemeSettings( required name, required struct settings ){ + function saveThemeSettings( required name, required struct settings ) { var oSite = variables.siteService.getCurrentWorkingSite(); transaction { // Filter out settings that are not theme based - arguments.settings - .filter( function( key, value ){ - return ( findNoCase( "cb_theme_#name#_", key ) ? true : false ); - } ) - .each( function( key, value ){ - var oSetting = variables.settingService.findSiteSetting( oSite, key ); - - if ( isNull( oSetting ) ) { - oSetting = variables.settingService.new( { name : key } ); + arguments + .settings + .filter( + function( key, value ) { + return ( findNoCase( "cb_theme_#name#_", key ) ? true : false ); } + ) + .each( + function( key, value ) { + var oSetting = variables.settingService.findSiteSetting( oSite, key ); + + if ( isNull( oSetting ) ) { + oSetting = variables.settingService.new( { name: key } ); + } - oSetting.setValue( value ); - oSetting.setSite( oSite ); + oSetting.setValue( value ); + oSetting.setSite( oSite ); - variables.settingService.save( oSetting ); - } ); + variables.settingService.save( oSetting ); + } + ); } return this; @@ -268,8 +314,11 @@ component accessors="true" threadSafe singleton { /** * Get the current active theme record for the current working site */ - struct function getActiveTheme(){ - return getThemeRecord( variables.siteService.getCurrentWorkingSite().getActiveTheme() ); + struct function getActiveTheme() { + return getThemeRecord( variables + .siteService + .getCurrentWorkingSite() + .getActiveTheme() ); } /** @@ -277,7 +326,7 @@ component accessors="true" threadSafe singleton { * * @themeName The name of the theme */ - struct function getThemeRecord( required themeName ){ + struct function getThemeRecord( required themeName ) { return variables.themeRegistry[ arguments.themeName ]; } @@ -286,7 +335,7 @@ component accessors="true" threadSafe singleton { * * @themeName The name of the theme to check */ - boolean function isActiveTheme( required themeName ){ + boolean function isActiveTheme( required themeName ) { return ( compareNoCase( getActiveTheme().name, arguments.themeName ) EQ 0 ); } @@ -295,20 +344,20 @@ component accessors="true" threadSafe singleton { * * @themeName The theme name to activate */ - function activateTheme( required themeName ){ + function activateTheme( required themeName ) { transaction { var currentSite = variables.siteService.getCurrentWorkingSite(); var themeRecord = getThemeRecord( currentSite.getActiveTheme() ); // Call deactivation event for the previous active theme variables.interceptorService.announce( - "cbadmin_onThemeDeactivation", - { - themeName : currentSite.getActiveTheme(), - themeRecord : themeRecord, - site : currentSite - } - ); + "cbadmin_onThemeDeactivation", + { + themeName : currentSite.getActiveTheme(), + themeRecord: themeRecord, + site : currentSite + } + ); // Call Old Theme Callback: onDeactivation if ( structKeyExists( themeRecord.descriptor, "onDeactivation" ) ) { @@ -322,8 +371,8 @@ component accessors="true" threadSafe singleton { // Unregister theme Descriptor Interceptor variables.interceptorService.unregister( - interceptorName = "cbTheme-#currentSite.getActiveTheme()#-#currentSite.getsiteID()#" - ); + interceptorName = "cbTheme-#currentSite.getActiveTheme()#-#currentSite.getsiteID()#" + ); // Setup the new chosen theme for the site currentSite.setActiveTheme( arguments.themeName ); @@ -342,7 +391,7 @@ component accessors="true" threadSafe singleton { /** * Get all registered themes via the registry. */ - struct function getThemes(){ + struct function getThemes() { if ( isSimpleValue( variables.themeRegistry ) ) { buildThemeRegistry(); } @@ -352,42 +401,48 @@ component accessors="true" threadSafe singleton { /** * Get all registered custom themes via the registry. */ - struct function getCustomThemes(){ + struct function getCustomThemes() { if ( isSimpleValue( variables.themeRegistry ) ) { buildThemeRegistry(); } - return variables.themeRegistry.filter( function( item, contents ){ - return ( contents.type == "custom" ? true : false ); - } ); + return variables.themeRegistry.filter( + function( item, contents ) { + return ( contents.type == "custom" ? true : false ); + } + ); } /** * Build the theme registry via discovery */ - ThemeService function buildThemeRegistry(){ + ThemeService function buildThemeRegistry() { // Get Core Themes and Process Them - getThemesOnDisk( variables.coreThemesPath ).each( function( item ){ - processThemeRecord( - name = arguments.item, - path = variables.coreThemesPath, - invocationPath = variables.moduleSettings[ "contentbox" ].invocationPath & ".themes", - includePath = variables.moduleSettings[ "contentbox" ].mapping & "/themes", - type = "core", - module = "contentbox" + getThemesOnDisk( variables.coreThemesPath ).each( + function( item ) { + processThemeRecord( + name = arguments.item, + path = variables.coreThemesPath, + invocationPath = variables.moduleSettings[ "contentbox" ].invocationPath & ".themes", + includePath = variables.moduleSettings[ "contentbox" ].mapping & "/themes", + type = "core", + module = "contentbox" + ); + } ); - } ); // Get Custom Themes and Process Them - getThemesOnDisk( variables.customThemesPath ).each( function( item ){ - processThemeRecord( - name = arguments.item, - path = variables.customThemesPath, - invocationPath = variables.moduleSettings[ "contentbox-custom" ].invocationPath & "._themes", - includePath = variables.moduleSettings[ "contentbox-custom" ].mapping & "/_themes", - type = "custom", - module = "contentbox-custom" + getThemesOnDisk( variables.customThemesPath ).each( + function( item ) { + processThemeRecord( + name = arguments.item, + path = variables.customThemesPath, + invocationPath = variables.moduleSettings[ "contentbox-custom" ].invocationPath & "._themes", + includePath = variables.moduleSettings[ "contentbox-custom" ].mapping & "/_themes", + type = "custom", + module = "contentbox-custom" + ); + } ); - } ); return this; } @@ -409,39 +464,41 @@ component accessors="true" threadSafe singleton { includePath, type, module - ){ + ) { var record = { - "name" : arguments.name, - "descriptor" : "", - "type" : arguments.type, - "module" : arguments.module, - "isValid" : false, - "path" : arguments.path, - "invocationPath" : arguments.invocationPath & "." & arguments.name, - "includePath" : arguments.includePath & "/" & arguments.name, - "themeName" : "", - "description" : "", - "version" : "", - "author" : "", - "authorURL" : "", - "screenShotURL" : "", - "forgeBoxSlug" : "", - "customInterceptionPoints" : "", - "layouts" : "", - "settings" : "", - "widgets" : "", - "modules" : "" + "name" : arguments.name, + "descriptor" : "", + "type" : arguments.type, + "module" : arguments.module, + "isValid" : false, + "path" : arguments.path, + "invocationPath" : arguments.invocationPath & "." & arguments.name, + "includePath" : arguments.includePath & "/" & arguments.name, + "themeName" : "", + "description" : "", + "version" : "", + "author" : "", + "authorURL" : "", + "screenShotURL" : "", + "forgeBoxSlug" : "", + "customInterceptionPoints": "", + "layouts" : "", + "settings" : "", + "widgets" : "", + "modules" : "" }; // Check for theme descriptor by 'theme.cfc' or '#themeName#.cfc' - var descriptorPath = arguments.path & "/#arguments.name#/Theme.cfc"; + var descriptorPath = arguments.path & "/#arguments.name#/Theme.cfc"; var descriptorInstance = arguments.invocationPath & ".#arguments.name#.Theme"; if ( !fileExists( descriptorPath ) ) { // try by theme name instead - descriptorPath = arguments.path & "/#arguments.name#/#arguments.name#.cfc"; + descriptorPath = arguments.path & "/#arguments.name#/#arguments.name#.cfc"; descriptorInstance = arguments.invocationPath & ".#arguments.name#.#arguments.name#"; if ( !fileExists( descriptorPath ) ) { - log.warn( "The theme: #arguments.name# has no theme descriptor, skipping registration." ); + log.warn( + "The theme: #arguments.name# has no theme descriptor, skipping registration." + ); variables.themeRegistry[ arguments.name ] = record; return; } @@ -451,13 +508,13 @@ component accessors="true" threadSafe singleton { var oThemeConfig = wirebox.getInstance( descriptorInstance ); // Populate Record with it - record.descriptor = oThemeConfig; - record.isValid = true; - record.themeName = oThemeConfig.name; + record.descriptor = oThemeConfig; + record.isValid = true; + record.themeName = oThemeConfig.name; record.description = oThemeConfig.description; - record.version = oThemeConfig.version; - record.author = oThemeConfig.author; - record.authorURL = oThemeConfig.authorURL; + record.version = oThemeConfig.version; + record.author = oThemeConfig.author; + record.authorURL = oThemeConfig.authorURL; // Screenshot if ( structKeyExists( oThemeConfig, "screenShotURL" ) ) { record.screenShotURL = arguments.includePath & "/#arguments.name#/" & oThemeConfig.screenShotURL; @@ -522,15 +579,15 @@ component accessors="true" threadSafe singleton { // Store layout oThemeConfiguration CFC and theme metadata record variables.themeCFCRegistry[ arguments.name ] = oThemeConfig; - variables.themeRegistry[ arguments.name ] = record; - }; + variables.themeRegistry[ arguments.name ] = record; + } /** * Remove a custom theme only. * * @themeName The theme to remove */ - boolean function removeTheme( required themeName ){ + boolean function removeTheme( required themeName ) { // verify name or even if it exists if ( !len( arguments.themeName ) || !variables.themeRegistry.keyExists( arguments.themeName ) ) { return false; @@ -550,7 +607,7 @@ component accessors="true" threadSafe singleton { // Remove settings if ( structKeyExists( themeRecord.descriptor, "settings" ) ) { - unregisterThemeSettings( settings: themeRecord.descriptor.settings ); + unregisterThemeSettings( settings = themeRecord.descriptor.settings ); } // Remove from registry @@ -575,11 +632,11 @@ component accessors="true" threadSafe singleton { * * @themeName The name of the theme */ - struct function getSettingsConstraints( required themeName ){ + struct function getSettingsConstraints( required themeName ) { // Get theme CFC var oTheme = variables.themeRegistry[ arguments.themeName ].descriptor; // Verify it has settings, else return empty struct - if ( !structKeyExists( oTheme, "settings" ) OR !arrayLen( oTheme.settings ) ) { + if ( !structKeyExists( oTheme, "settings" ) || !arrayLen( oTheme.settings ) ) { return {}; } @@ -587,8 +644,8 @@ component accessors="true" threadSafe singleton { var constraints = {}; for ( var thisSetting in oTheme.settings ) { // Check if required - if ( structKeyExists( thisSetting, "required" ) and thisSetting.required ) { - constraints[ thisSetting.name ] = { required : true }; + if ( structKeyExists( thisSetting, "required" ) && thisSetting.required ) { + constraints[ thisSetting.name ] = { required: true }; } } @@ -600,206 +657,231 @@ component accessors="true" threadSafe singleton { * * @activeTheme The active theme struct */ - function buildSettingsForm( required struct activeTheme ){ + function buildSettingsForm( required struct activeTheme ) { // Get theme CFC - var oTheme = variables.themeRegistry[ arguments.activeTheme.name ].descriptor; - var oSite = variables.siteService.getCurrentWorkingSite(); + var oTheme = variables.themeRegistry[ arguments.activeTheme.name ].descriptor; + var oSite = variables.siteService.getCurrentWorkingSite(); var settingForm = ""; // Build Form by iteration over items - if ( !structKeyExists( oTheme, "settings" ) OR !arrayLen( oTheme.settings ) ) { + if ( !structKeyExists( oTheme, "settings" ) || !arrayLen( oTheme.settings ) ) { return settingForm; } - // cfformat-ignore-start + savecontent variable="settingForm" { +// Write out panel container +writeOutput( +"
      " +); + +// Iterate and create settings +var lastGroup = "NeverHadAGroup"; +var firstPanel = true; +for ( var x = 1; x LTE arrayLen( oTheme.settings ); x++ ) { +var thisSettingMD = oTheme.settings[ x ]; +var requiredText = ""; +var requiredValidator = ""; + +// get actual setting value which should be guaranteed to exist +var settingName = "cb_theme_#arguments.activeTheme.name#_#thisSettingMD.name#"; +var oSetting = settingService.findSiteSetting( oSite, settingName ); + +thisSettingMD.defaultValue = oSetting.getValue(); + +// Default values for settings +if ( !structKeyExists( thisSettingMD, "required" ) ) { +thisSettingMD.required = false; +} +if ( !structKeyExists( thisSettingMD, "label" ) ) { +thisSettingMD.label = thisSettingMD.name; +} +if ( !structKeyExists( thisSettingMD, "type" ) ) { +thisSettingMD.type = "text"; +} +if ( !structKeyExists( thisSettingMD, "title" ) ) { +thisSettingMD.title = ""; +} +if ( !structKeyExists( thisSettingMD, "group" ) ) { +thisSettingMD.group = "Main"; +} +if ( !structKeyExists( thisSettingMD, "groupIntro" ) ) { +thisSettingMD.groupIntro = ""; +} +if ( !structKeyExists( thisSettingMD, "fieldHelp" ) ) { +thisSettingMD.fieldHelp = ""; +} +if ( !structKeyExists( thisSettingMD, "fieldDescription" ) ) { +thisSettingMD.fieldDescription = ""; +} - savecontent variable="settingForm"{ - - // Write out panel container - writeOutput( '
      ' ); - - // Iterate and create settings - var lastGroup = "NeverHadAGroup"; - var firstPanel= true; - for( var x=1; x lte arrayLen( oTheme.settings ); x++ ){ - var thisSettingMD = oTheme.settings[ x ]; - var requiredText = ""; - var requiredValidator = ""; - - // get actual setting value which should be guaranteed to exist - var settingName = "cb_theme_#arguments.activeTheme.name#_#thisSettingMD.name#"; - var oSetting = settingService.findSiteSetting( oSite, settingName ); - - thisSettingMD.defaultValue = oSetting.getValue(); - - // Default values for settings - if( !structKeyExists( thisSettingMD, "required" ) ){ thisSettingMD.required = false; } - if( !structKeyExists( thisSettingMD, "label" ) ){ thisSettingMD.label = thisSettingMD.name; } - if( !structKeyExists( thisSettingMD, "type" ) ){ thisSettingMD.type = "text"; } - if( !structKeyExists( thisSettingMD, "title" ) ){ thisSettingMD.title = ""; } - if( !structKeyExists( thisSettingMD, "group" ) ){ thisSettingMD.group = "Main"; } - if( !structKeyExists( thisSettingMD, "groupIntro" ) ){ thisSettingMD.groupIntro = ""; } - if( !structKeyExists( thisSettingMD, "fieldHelp" ) ){ thisSettingMD.fieldHelp = ""; } - if( !structKeyExists( thisSettingMD, "fieldDescription" ) ){ thisSettingMD.fieldDescription = ""; } - - // required static strings - if( thisSettingMD.required ){ - requiredText = "*Required"; - requiredValidator = "required"; - } - - // Starting a group panel? - if ( thisSettingMD.group != lastGroup ){ - - // Close out previous group panel-body - if ( lastGroup != "NeverHadAGroup" ){ - writeOutput( "
      " ); - } - - // Write out group panel header - writeOutput( '
      ' ); - if ( thisSettingMD.group != "" ){ - writeOutput( ' - - '); - } - - // Start group body panel - writeOutput( ' -
      -
      - ' ); - - // Show group intro if there is one - if( len( thisSettingMD.groupIntro ) ){ - writeOutput( '
      ' & thisSettingMD.groupIntro & '
      ' ); - } - - // Set this as the last group - lastGroup = thisSettingMD.group; - firstpanel = false; - } +// required static strings +if ( thisSettingMD.required ) { +requiredText = "*Required"; +requiredValidator = "required"; +} - // writeout control wrapper - writeOutput( '
      ' ); +// Starting a group panel? +if ( thisSettingMD.group != lastGroup ) { +// Close out previous group panel-body +if ( lastGroup != "NeverHadAGroup" ) { +writeOutput( "
      " ); +} - // write out label - writeOutput( html.label( field=settingName, content="#thisSettingMD.label# #requiredText#" ) ); +// Write out group panel header +writeOutput( "
      " ); +if ( thisSettingMD.group != "" ) { +writeOutput( +" + + " +); +} - // Generate question mark icon for field Help to open modal - if( len( thisSettingMD.fieldHelp ) ){ - writeOutput( ' ' ); - } +// Start group body panel +writeOutput( +" +
      +
      +" +); + +// Show group intro if there is one +if ( len( thisSettingMD.groupIntro ) ) { +writeOutput( +"
      " & thisSettingMD.groupIntro & "
      " +); +} +// Set this as the last group +lastGroup = thisSettingMD.group; +firstpanel = false; +} - // write out field description - if( len( thisSettingMD.fieldDescription ) ){ - writeOutput( '
      ' & thisSettingMD.fieldDescription & '
      ' ); - } +// writeout control wrapper +writeOutput( "
      " ); + +// write out label +writeOutput( +html.label( +field = settingName, +content = "#thisSettingMD.label# #requiredText#" +) +); + +// Generate question mark icon for field Help to open modal +if ( len( thisSettingMD.fieldHelp ) ) { +writeOutput( +" " +); +} - // write out control - switch( thisSettingMD.type ){ - case "boolean" : { - writeOutput( - html.select( - name = settingName, - options = "true,false", - selectedValue= thisSettingMD.defaultValue, - title = thisSettingMD.title, - class = "form-control input-lg" - ) - ); - break; - } - case "select" : { - var options = ""; - // Check options UDF - if( structKeyExists( thisSettingMD, "optionsUDF" ) ){ - options = invoke( oTheme, thisSettingMD.optionsUDF ); - } else if( structKeyExists( thisSettingMD, "options" ) ){ - options = thisSettingMD.options; - } - writeOutput( - html.select( - name = settingName, - options = options, - selectedValue= thisSettingMD.defaultValue, - title = thisSettingMD.title, - class = "form-control input-lg" - ) - ); - break; - } - case "textarea" : { - writeOutput( - html.textarea( - name = settingName, - required= requiredValidator, - title = thisSettingMD.title, - value = thisSettingMD.defaultValue, - class = "form-control", - rows = 5 - ) - ); - break; - } - case "color" : { - writeOutput( - html.inputField( - name = settingName, - class = "textfield", - required= requiredValidator, - title = thisSettingMD.title, - value = thisSettingMD.defaultValue, - class = "form-control", - type = "color" - ) - ); - break; - } - default:{ - writeOutput( - html.textfield( - name = settingName, - class = "textfield", - required= requiredValidator, - title = thisSettingMD.title, - value = thisSettingMD.defaultValue, - class = "form-control" - ) - ); - } - } +// write out field description +if ( len( thisSettingMD.fieldDescription ) ) { +writeOutput( "
      " & thisSettingMD.fieldDescription & "
      " ); +} - // End form group - writeOutput( '
      ' ); +// write out control +switch ( thisSettingMD.type ) { +case "boolean": { +writeOutput( +html.select( + name = settingName, + options = "true,false", + selectedValue = thisSettingMD.defaultValue, + title = thisSettingMD.title, + class = "form-control input-lg" + ) +); +break; +} +case "select": { +var options = ""; +// Check options UDF +if ( structKeyExists( thisSettingMD, "optionsUDF" ) ) { +options = invoke( oTheme, thisSettingMD.optionsUDF ); +} else if ( structKeyExists( thisSettingMD, "options" ) ) { +options = thisSettingMD.options; +} +writeOutput( +html.select( + name = settingName, + options = options, + selectedValue = thisSettingMD.defaultValue, + title = thisSettingMD.title, + class = "form-control input-lg" + ) +); +break; +} +case "textarea": { +writeOutput( +html.textarea( + name = settingName, + required = requiredValidator, + title = thisSettingMD.title, + value = thisSettingMD.defaultValue, + class = "form-control", + rows = 5 + ) +); +break; +} +case "color": { +writeOutput( +html.inputField( + name = settingName, + class = "textfield", + required = requiredValidator, + title = thisSettingMD.title, + value = thisSettingMD.defaultValue, + class = "form-control", + type = "color" + ) +); +break; +} +default: { +writeOutput( +html.textfield( + name = settingName, + class = "textfield", + required = requiredValidator, + title = thisSettingMD.title, + value = thisSettingMD.defaultValue, + class = "form-control" + ) +); +} +} - // Generate modal for field Help - if( len( thisSettingMD.fieldHelp ) ){ - writeOutput( generateModal( settingName, thisSettingMD ) ); - } +// End form group +writeOutput( "
      " ); - } // end looping over theme settings +// Generate modal for field Help +if ( len( thisSettingMD.fieldHelp ) ) { +writeOutput( generateModal( settingName, thisSettingMD ) ); +} +} // end looping over theme settings - // Finalize Group Panel: In case we only had one setting in this group. - if ( lastGroup != "NeverHadAGroup" ){ - writeOutput( '
      ' ); - } +// Finalize Group Panel: In case we only had one setting in this group. +if ( lastGroup != "NeverHadAGroup" ) { +writeOutput( "
      " ); +} - // Finalize Container - writeOutput( "" ); - } +// Finalize Container +writeOutput( "" ); +} // cfformat-ignore-end @@ -812,24 +894,26 @@ component accessors="true" threadSafe singleton { * @settingName - The name of the setting the Theme Setting Help modal will be created for * @thisSettingMD - The setting struct itself */ - function generateModal( required settingName, required thisSettingMD ){ + function generateModal( required settingName, required thisSettingMD ) { // cfformat-ignore-start - return ''; + return "
      +
      +
      +
      + +

      #arguments.thisSettingMD.label#

      +
      +
      + #arguments.thisSettingMD.fieldHelp# +
      +
      + +
      +
      +
      +
      "; + + // cfformat-ignore-end } @@ -840,15 +924,22 @@ component accessors="true" threadSafe singleton { * * @path The path to check */ - private array function getThemesOnDisk( required path ){ - return directoryList( arguments.path, false, "name", "", "name asc" ).filter( function( item ){ - // exclude .* - if ( left( item, 1 ) eq "." ) { - return false; - } - // exclude files - return ( directoryExists( path & "/" & item ) ? true : false ); - } ); + private array function getThemesOnDisk( required path ) { + return directoryList( + arguments.path, + false, + "name", + "", + "name asc" + ).filter( + function( item ) { + if ( left( item, 1 ) EQ "." ) { + return false; + } + + return ( directoryExists( path & "/" & item ) ? true : false ); + } + ); } /** @@ -858,12 +949,13 @@ component accessors="true" threadSafe singleton { * * @return ThemeService */ - private function unregisterThemeSettings( required array settings ){ + private function unregisterThemeSettings( required array settings ) { transaction { // iterate and register theme settings for ( var thisSetting in arguments.settings ) { // try to retrieve the collection - var aSettings = variables.settingService + var aSettings = variables + .settingService .newCriteria() .isEq( "name", "cb_theme_#arguments.name#_#thisSetting.name#" ) .list(); @@ -891,36 +983,44 @@ component accessors="true" threadSafe singleton { required name, required array settings, required site - ){ + ) { // Get all core, non-deleted setting names - var loadedSiteSettings = variables.settingService + var loadedSiteSettings = variables + .settingService .newCriteria() .isFalse( "isDeleted" ) .isEq( "site", arguments.site ) - .withProjections( property: "name" ) + .withProjections( property = "name" ) .list( sortOrder = "name" ); // Check what's missing transaction { - arguments.settings + arguments + .settings + .filter( + function( thisSetting ) { + return !arrayContainsNoCase( loadedSiteSettings, "cb_theme_#name#_#thisSetting.name#" ); + } + ) // only load defaults that do not exist - .filter( function( thisSetting ){ - return !arrayContainsNoCase( loadedSiteSettings, "cb_theme_#name#_#thisSetting.name#" ); - } ) + // Create the missing setting - .each( function( thisSetting ){ - variables.settingService.save( - variables.settingService - .new( { - name : "cb_theme_#name#_#thisSetting.name#", - value : thisSetting.defaultValue - } ) - .setSite( site ) - ); - } ); + .each( + function( thisSetting ) { + variables.settingService.save( variables + .settingService + .new( + { + name : "cb_theme_#name#_#thisSetting.name#", + value: thisSetting.defaultValue + } + ) + .setSite( site ) ); + } + ); } return this; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/ui/Widget.cfc b/modules/contentbox/models/ui/Widget.cfc index fbd91a4ec8..b9314635f0 100644 --- a/modules/contentbox/models/ui/Widget.cfc +++ b/modules/contentbox/models/ui/Widget.cfc @@ -6,31 +6,36 @@ * I represent a new widget to be created in the ContentBox System */ component accessors="true" { - property name="name"; + property name="version"; + property name="description"; + property name="author"; + property name="authorURL"; + property name="category"; + property name="icon"; - Widget function init(){ - variables.name = ""; - variables.version = ""; + Widget function init() { + variables.name = ""; + variables.version = ""; variables.description = ""; - variables.author = ""; - variables.authorURL = ""; - variables.category = ""; - variables.icon = ""; + variables.author = ""; + variables.authorURL = ""; + variables.category = ""; + variables.icon = ""; return this; } /* * Validate entry, returns an array of error or no messages */ - array function validate(){ - var errors = []; + array function validate() { + var errors = []; var aRequired = listToArray( "name,version,description,author,authorURL" ); // Required @@ -43,4 +48,4 @@ component accessors="true" { return errors; } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/ui/WidgetService.cfc b/modules/contentbox/models/ui/WidgetService.cfc index 718bf81f06..e29162c5bc 100644 --- a/modules/contentbox/models/ui/WidgetService.cfc +++ b/modules/contentbox/models/ui/WidgetService.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -6,14 +6,19 @@ * Manages ContentBox Widgets */ component accessors="true" singleton threadSafe { - // Dependecnies property name="settingService" inject="id:settingService@contentbox"; + property name="moduleSettings" inject="coldbox:setting:modules"; + property name="moduleService" inject="ModuleService@contentbox"; + property name="themeService" inject="themeService@contentbox"; + property name="wirebox" inject="wirebox"; + property name="coldbox" inject="coldbox"; + property name="log" inject="logbox:logger:{this}"; /** @@ -44,8 +49,8 @@ component accessors="true" singleton threadSafe { /** * Constructor */ - WidgetService function init(){ - variables.coreWidgetsMap = {}; + WidgetService function init() { + variables.coreWidgetsMap = {}; variables.customWidgetsMap = {}; variables.loadedWidgets = ""; @@ -55,16 +60,16 @@ component accessors="true" singleton threadSafe { /** * onDIComplete */ - function onDIComplete(){ + function onDIComplete() { // Verify widgets path location - variables.coreWidgetsPath = variables.moduleSettings[ "contentbox" ].path & "/widgets"; + variables.coreWidgetsPath = variables.moduleSettings[ "contentbox" ].path & "/widgets"; variables.customWidgetsPath = variables.moduleSettings[ "contentbox-custom" ].path & "/_widgets"; } /** * Get installed widgets as an array of names */ - array function getWidgetsList(){ + array function getWidgetsList() { var w = getWidgets(); return listToArray( valueList( w.name ) ); } @@ -73,9 +78,9 @@ component accessors="true" singleton threadSafe { * Get unique, sorted widget categories from main widget query * returns Query */ - query function getWidgetCategories(){ + query function getWidgetCategories() { var widgets = getWidgets(); - var q = new Query( + var q = new Query( dbType = "query", QoQ = widgets, sql = "select distinct category from QoQ order by category ASC" @@ -92,24 +97,60 @@ component accessors="true" singleton threadSafe { * * @reload Widgets are lazy loaded, or you can force a reload */ - query function getWidgets( boolean reload = false ){ + query function getWidgets( boolean reload = false ) { // If query is loaded and not a reload then return it. - if ( isQuery( variables.loadedWidgets ) and !arguments.reload ) { + if ( isQuery( variables.loadedWidgets ) && !arguments.reload ) { return variables.loadedWidgets; } var qAllWidgets = queryNew( "" ); // Add custom columns - queryAddColumn( qAllWidgets, "name", [] ); - queryAddColumn( qAllWidgets, "directory", [] ); - queryAddColumn( qAllWidgets, "filename", [] ); - queryAddColumn( qAllWidgets, "widgettype", [] ); - queryAddColumn( qAllWidgets, "module", [] ); - queryAddColumn( qAllWidgets, "category", [] ); - queryAddColumn( qAllWidgets, "icon", [] ); - queryAddColumn( qAllWidgets, "debug", [] ); - queryAddColumn( qAllWidgets, "invocationPath", [] ); + queryAddColumn( + qAllWidgets, + "name", + [] + ); + queryAddColumn( + qAllWidgets, + "directory", + [] + ); + queryAddColumn( + qAllWidgets, + "filename", + [] + ); + queryAddColumn( + qAllWidgets, + "widgettype", + [] + ); + queryAddColumn( + qAllWidgets, + "module", + [] + ); + queryAddColumn( + qAllWidgets, + "category", + [] + ); + queryAddColumn( + qAllWidgets, + "icon", + [] + ); + queryAddColumn( + qAllWidgets, + "debug", + [] + ); + queryAddColumn( + qAllWidgets, + "invocationPath", + [] + ); processWidgets( qAllWidgets, "Core" ) .processWidgets( qAllWidgets, "Custom" ) @@ -128,18 +169,22 @@ component accessors="true" singleton threadSafe { * @qRecords The records query to attach yourself to * @type The type to process */ - WidgetService function processWidgets( query qRecords = getLoadedWidgets(), type ){ + WidgetService function processWidgets( query qRecords = getLoadedWidgets(), type ) { // get core widgets to start with. var qWidgets = getWidgetsFromPath( ( arguments.type == "Core" ? variables.coreWidgetsPath : variables.customWidgetsPath ) ); // Iterate and incorporate extra metadata to record - for ( var x = 1; x lte qWidgets.recordCount; x++ ) { + for ( var x = 1; x LTE qWidgets.recordCount; x++ ) { var widgetName = ripExtension( qWidgets.name[ x ] ); // Add new row with data queryAddRow( arguments.qRecords ); - querySetCell( arguments.qRecords, "name", widgetName ); + querySetCell( + arguments.qRecords, + "name", + widgetName + ); querySetCell( arguments.qRecords, "directory", @@ -187,7 +232,7 @@ component accessors="true" singleton threadSafe { "icon", getWidgetIcon( oWidget, arguments.type ) ); - } catch ( any e ) { + } catch (any e) { log.error( "Error creating #arguments.type# widget: #widgetName#", e ); querySetCell( arguments.qRecords, @@ -205,21 +250,45 @@ component accessors="true" singleton threadSafe { * * @qRecords The records query to attach yourself to */ - WidgetService function processModuleWidgets( query qRecords = getLoadedWidgets() ){ + WidgetService function processModuleWidgets( query qRecords = getLoadedWidgets() ) { // get module widgets var moduleWidgets = moduleService.getModuleWidgetCache(); // add module widgets for ( var widget in moduleWidgets ) { var thisRecord = moduleWidgets[ widget ]; - var widgetName = listGetAt( widget, 1, "@" ); - var moduleName = listGetAt( widget, 2, "@" ); + var widgetName = listGetAt( + widget, + 1, + "@" + ); + var moduleName = listGetAt( + widget, + 2, + "@" + ); // Add new row with data queryAddRow( arguments.qRecords ); - querySetCell( arguments.qRecords, "name", widgetName ); - querySetCell( arguments.qRecords, "filename", widgetName ); - querySetCell( arguments.qRecords, "widgettype", "Module" ); - querySetCell( arguments.qRecords, "module", moduleName ); + querySetCell( + arguments.qRecords, + "name", + widgetName + ); + querySetCell( + arguments.qRecords, + "filename", + widgetName + ); + querySetCell( + arguments.qRecords, + "widgettype", + "Module" + ); + querySetCell( + arguments.qRecords, + "module", + moduleName + ); querySetCell( arguments.qRecords, "directory", @@ -243,8 +312,11 @@ component accessors="true" singleton threadSafe { "icon", getWidgetIcon( name = oWidget, type = "module" ) ); - } catch ( any e ) { - log.error( "Error creating module (#moduleName#) widget: #widgetName#", e ); + } catch (any e) { + log.error( + "Error creating module (#moduleName#) widget: #widgetName#", + e + ); querySetCell( arguments.qRecords, "debug", @@ -261,7 +333,7 @@ component accessors="true" singleton threadSafe { * * @qRecords The records query to attach yourself to */ - WidgetService function processThemeWidgets( query qRecords = getLoadedWidgets() ){ + WidgetService function processThemeWidgets( query qRecords = getLoadedWidgets() ) { // get theme widgets var themeWidgets = themeService.getWidgetCache(); @@ -270,9 +342,21 @@ component accessors="true" singleton threadSafe { var thisRecord = themeWidgets[ widget ]; queryAddRow( qRecords ); - querySetCell( qRecords, "name", widget ); - querySetCell( qRecords, "filename", widget ); - querySetCell( qRecords, "widgettype", "Theme" ); + querySetCell( + qRecords, + "name", + widget + ); + querySetCell( + qRecords, + "filename", + widget + ); + querySetCell( + qRecords, + "widgettype", + "Theme" + ); querySetCell( qRecords, "invocationPath", @@ -296,8 +380,11 @@ component accessors="true" singleton threadSafe { "icon", getWidgetIcon( name = oWidget, type = "theme" ) ); - } catch ( any e ) { - log.error( "Error creating theme (#thisRecord.theme#) widget: #widget#", e ); + } catch (any e) { + log.error( + "Error creating theme (#thisRecord.theme#) widget: #widget#", + e + ); querySetCell( qRecords, "debug", @@ -315,9 +402,9 @@ component accessors="true" singleton threadSafe { * * @name The name of the widget */ - string function discoverWidgetType( required name ){ + string function discoverWidgetType( required name ) { var isCustom = false; - var isTheme = false; + var isTheme = false; var qWidgets = getWidgets(); for ( var thisRow in qWidgets ) { @@ -348,9 +435,9 @@ component accessors="true" singleton threadSafe { * * @name The convention name */ - any function getWidgetByDiscovery( required name ){ + any function getWidgetByDiscovery( required name ) { var isModuleWidget = findNoCase( "@", arguments.name ) ? true : false; - var isThemeWidget = findNoCase( "~", arguments.name ) ? true : false; + var isThemeWidget = findNoCase( "~", arguments.name ) ? true : false; if ( isModuleWidget ) { return getWidget( arguments.name, "module" ); @@ -372,7 +459,7 @@ component accessors="true" singleton threadSafe { * * @throws WidgetNotFoundException */ - any function getWidget( required name, required string type = "core" ){ + any function getWidget( required name, required string type = "core" ) { var widgetPath = ""; switch ( arguments.type ) { @@ -392,7 +479,10 @@ component accessors="true" singleton threadSafe { if ( len( widgetPath ) ) { // Init Arguments added for backwards compat - return wirebox.getInstance( name = widgetPath, initArguments = { "controller" : variables.coldbox } ); + return wirebox.getInstance( + name = widgetPath, + initArguments = { "controller": variables.coldbox } + ); } else { throw( message = "The widget (#arguments.name#) could not be located anywhere.", @@ -407,7 +497,7 @@ component accessors="true" singleton threadSafe { * @name The name of the widget or the widget instance * @type This can be one of the following: core, theme, module */ - string function getWidgetIcon( required name, required string type = "core" ){ + string function getWidgetIcon( required name, required string type = "core" ) { if ( isSimpleValue( arguments.name ) ) { var widget = getWidget( argumentCollection = arguments ); } else { @@ -436,7 +526,7 @@ component accessors="true" singleton threadSafe { * @name The name of the widget or the actual widget object * @type This can be one of the following: core, theme, module */ - string function getWidgetCategory( required name, required string type = "core" ){ + string function getWidgetCategory( required name, required string type = "core" ) { if ( isSimpleValue( arguments.name ) ) { var widget = getWidget( argumentCollection = arguments ); } else { @@ -464,7 +554,7 @@ component accessors="true" singleton threadSafe { * * @widgetFile The location of the widget to remove */ - boolean function removeWidget( required widgetFile ){ + boolean function removeWidget( required widgetFile ) { var wCustomPath = variables.customWidgetsPath & "/" & arguments.widgetFile & ".cfc"; if ( fileExists( wCustomPath ) ) { @@ -483,8 +573,12 @@ component accessors="true" singleton threadSafe { * * @fileName The target to rip */ - function ripExtension( required filename ){ - return reReplace( arguments.filename, "\.[^.]*$", "" ); + function ripExtension( required filename ) { + return reReplace( + arguments.filename, + "\.[^.]*$", + "" + ); } /** @@ -496,7 +590,7 @@ component accessors="true" singleton threadSafe { * * @return The argument metadata structure */ - function getWidgetRenderArgs( required udf, required widget, required type ){ + function getWidgetRenderArgs( required udf, required widget, required type ) { // get widget var p = getWidget( name = arguments.widget, type = arguments.type ); return getMetadata( p[ udf ] ); @@ -507,7 +601,7 @@ component accessors="true" singleton threadSafe { * * @path The path to check */ - private query function getWidgetsFromPath( required path ){ + private query function getWidgetsFromPath( required path ) { return directoryList( arguments.path, false, @@ -517,4 +611,4 @@ component accessors="true" singleton threadSafe { ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/ui/editors/EditorService.cfc b/modules/contentbox/models/ui/editors/EditorService.cfc index 53edb21b30..5757ccbab4 100755 --- a/modules/contentbox/models/ui/editors/EditorService.cfc +++ b/modules/contentbox/models/ui/editors/EditorService.cfc @@ -6,7 +6,6 @@ * Manages editor contributions within ContentBox */ component accessors="true" threadSafe singleton { - // DI property name="settingService" inject="settingService@contentbox"; @@ -25,7 +24,7 @@ component accessors="true" threadSafe singleton { * * @wirebox.inject wirebox */ - EditorService function init( required wirebox ){ + EditorService function init( required wirebox ) { // init editors and markups variables.editors = {}; variables.markups = []; @@ -42,14 +41,14 @@ component accessors="true" threadSafe singleton { /** * Get the default system editor */ - string function getDefaultEditor(){ + string function getDefaultEditor() { return variables.settingService.getSetting( "cb_editors_default" ); } /** * Get the default system markup */ - string function getDefaultMarkup(){ + string function getDefaultMarkup() { return variables.settingService.getSetting( "cb_editors_markup" ); } @@ -58,7 +57,9 @@ component accessors="true" threadSafe singleton { * * @editor The editor instance to register */ - EditorService function registerEditor( required contentbox.models.ui.editors.IEditor editor ){ + EditorService function registerEditor( + required contentbox.models.ui.editors.IEditor editor + ) { variables.editors[ arguments.editor.getName() ] = arguments.editor; return this; } @@ -68,7 +69,7 @@ component accessors="true" threadSafe singleton { * * @markup The markup name to register */ - EditorService function registerMarkup( required markup ){ + EditorService function registerMarkup( required markup ) { arrayAppend( variables.markups, arguments.markup ); return this; } @@ -78,7 +79,7 @@ component accessors="true" threadSafe singleton { * * @name The name of the editor to unregister */ - EditorService function unRegisterEditor( required name ){ + EditorService function unRegisterEditor( required name ) { structDelete( variables.editors, arguments.name ); return this; } @@ -88,15 +89,18 @@ component accessors="true" threadSafe singleton { * * @markup The markup name to unregister */ - EditorService function unRegisterMarkup( required markup ){ - arrayDeleteAt( variables.markups, arrayFindNoCase( variables.markups, arguments.markup ) ); + EditorService function unRegisterMarkup( required markup ) { + arrayDeleteAt( + variables.markups, + arrayFindNoCase( variables.markups, arguments.markup ) + ); return this; } /** * Get an array of registered editor names in alphabetical order */ - array function getRegisteredEditors(){ + array function getRegisteredEditors() { var sortedArray = variables.editors.keyArray(); sortedArray.sort( "textnocase" ); return sortedArray; @@ -105,7 +109,7 @@ component accessors="true" threadSafe singleton { /** * Get an array of registered markup names in alphabetical order */ - array function getRegisteredMarkups(){ + array function getRegisteredMarkups() { arraySort( variables.markups, "textnocase" ); return variables.markups; } @@ -113,15 +117,15 @@ component accessors="true" threadSafe singleton { /** * Get an array of registered editor names in alphabetical order with their display names */ - array function getRegisteredEditorsMap(){ + array function getRegisteredEditorsMap() { var aEditors = getRegisteredEditors(); - var result = []; + var result = []; for ( var thisEditor in aEditors ) { arrayAppend( result, { - name : thisEditor, - displayName : variables.editors[ thisEditor ].getDisplayName() + name : thisEditor, + displayName: variables.editors[ thisEditor ].getDisplayName() } ); } @@ -133,7 +137,7 @@ component accessors="true" threadSafe singleton { * * @name The name of the editor */ - contentbox.models.ui.editors.IEditor function getEditor( required name ){ + contentbox.models.ui.editors.IEditor function getEditor( required name ) { return variables.editors[ arguments.name ]; } @@ -142,7 +146,7 @@ component accessors="true" threadSafe singleton { * * @name The name of the editor */ - boolean function hasEditor( required name ){ + boolean function hasEditor( required name ) { return structKeyExists( variables.editors, arguments.name ); } @@ -151,8 +155,8 @@ component accessors="true" threadSafe singleton { * * @markup The name of the markup */ - boolean function hasMarkup( required markup ){ + boolean function hasMarkup( required markup ) { return structKeyExists( variables.markups, arguments.name ); } -} +} \ No newline at end of file diff --git a/modules/contentbox/models/ui/editors/IEditor.cfc b/modules/contentbox/models/ui/editors/IEditor.cfc index 684ff6fb63..c4d78686ab 100644 --- a/modules/contentbox/models/ui/editors/IEditor.cfc +++ b/modules/contentbox/models/ui/editors/IEditor.cfc @@ -21,11 +21,13 @@ interface { * This is fired once editor javascript loads, you can use this to return back functions, asset calls, etc. * return the appropriate JavaScript. * Each editor must implement the following JS functions: - * checkIsDirty() - Checks if the editor has detected any changes
      - * getEditorContent() - Get's the HTML value of the content field
      - * getEditorExcerpt() - Get's the HTML value of the excerpt field
      - * updateEditorContent() - Updates the HTML value of the content field from the editor (if editor supports it)
      - * updateEditorExcerpt() - Updates the HTML value of the excerpt field from the editor (if editor supports it)
      + *
      +	 * - checkIsDirty() - Checks if the editor has detected any changes
      +	 * - getEditorContent() - Get the HTML value of the content field
      +	 * - getEditorExcerpt() - Get the HTML value of the excerpt field
      +	 * - updateEditorContent() - Updates the HTML value of the content field from the editor (if editor supports it)
      +	 * - updateEditorExcerpt() - Updates the HTML value of the excerpt field from the editor (if editor supports it)
      +	 * 
      */ function loadAssets(); @@ -40,5 +42,4 @@ interface { * return the appropriate JavaScript to turn off the editor. */ function shutdown(); - -} +} \ No newline at end of file diff --git a/modules/contentbox/models/ui/templates/messagebox.cfm b/modules/contentbox/models/ui/templates/messagebox.cfm index 7715eb7634..4856c67dfd 100644 --- a/modules/contentbox/models/ui/templates/messagebox.cfm +++ b/modules/contentbox/models/ui/templates/messagebox.cfm @@ -1,44 +1,54 @@ - switch( msgStruct.type ){ - case "info" : { + switch ( msgStruct.type ) { + case "info": { local.cssType = " alert-info"; local.iconType = "fa fa-info-circle"; break; } - case "error" : { + case "error": { local.cssType = " alert-danger"; local.iconType = "fa fa-frown-o"; break; } - case "success" : { + case "success": { local.cssType = " alert-success"; local.iconType = "fa fa-frown-o"; break; } - case "dark" : { + case "dark": { local.cssType = " alert-dark"; local.iconType = "fa fa-frown-o"; break; } - case "light" : { + case "light": { local.cssType = " alert-light"; local.iconType = "fa fa-frown-o"; break; } - default : { + default: { local.cssType = " alert-warning"; local.iconType = "fa fa-exclamation-triangle"; } } -
      - - +
      + + #msgStruct.message# #msgStruct.message.toString()# + + + + +
      + + + + + \ No newline at end of file diff --git a/modules/contentbox/models/ui/templates/navAdminMenu.cfm b/modules/contentbox/models/ui/templates/navAdminMenu.cfm index 666b47cade..b21b96fd1f 100644 --- a/modules/contentbox/models/ui/templates/navAdminMenu.cfm +++ b/modules/contentbox/models/ui/templates/navAdminMenu.cfm @@ -1,54 +1,154 @@ -
      +
      + + + + + + + +
      + + + + +
      + + + +
      +
      + + +
      + + +
      +
      +
      + + + + + + +
      + + + + + +
      +
      +
      + +
      +
      0
      +
      Passed
      +
      +
      + +
      +
      0
      +
      Failed
      +
      +
      + +
      +
      0
      +
      Errored
      +
      +
      + +
      +
      0
      +
      Skipped
      +
      +
      +
      + +
      + + + + + + + + +
      + +
      + +
      + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/tests/resources/config/Coldbox.cfc b/tests/resources/config/Coldbox.cfc index f7de41c7b7..9c55a5b250 100755 --- a/tests/resources/config/Coldbox.cfc +++ b/tests/resources/config/Coldbox.cfc @@ -122,4 +122,4 @@ component { // logbox.debug = [ "root" ]; } -} +} \ No newline at end of file diff --git a/tests/runner.bxm b/tests/runner.bxm new file mode 100755 index 0000000000..b281326be5 --- /dev/null +++ b/tests/runner.bxm @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/runner.cfm b/tests/runner.cfm index 4716b800b3..91e4d5d348 100644 --- a/tests/runner.cfm +++ b/tests/runner.cfm @@ -1,22 +1,36 @@ - - - - - - - + + + + + + + + + + + + + - + + + - - + + + + + + + + diff --git a/tests/specs/contentbox-api/AuthorsSpec.cfc b/tests/specs/contentbox-api/AuthorsSpec.cfc index 0c8be7a043..7cca434ee5 100644 --- a/tests/specs/contentbox-api/AuthorsSpec.cfc +++ b/tests/specs/contentbox-api/AuthorsSpec.cfc @@ -1,8 +1,10 @@ component extends="tests.resources.BaseApiTest" { - property name="siteService" inject="siteService@contentbox"; + property name="authorService" inject="authorService@contentbox"; + property name="roleService" inject="roleService@contentbox"; + property name="permissionService" inject="permissionService@contentbox"; /*********************************** LIFE CYCLE Methods ***********************************/ @@ -10,7 +12,7 @@ component extends="tests.resources.BaseApiTest" { /** * executes before all suites+specs in the run() method */ - function beforeAll(){ + function beforeAll() { super.beforeAll(); // Log in admin variables.loggedInData = loginUser(); @@ -19,204 +21,333 @@ component extends="tests.resources.BaseApiTest" { /** * executes after all suites+specs in the run() method */ - function afterAll(){ + function afterAll() { super.afterAll(); } /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ + function run( testResults, testBox ) { // all your suites go here. - describe( "Authors API Suite", function(){ - beforeEach( function( currentSpec ){ - // Setup as a new ColdBox request for this suite, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST. - setup(); - } ); + describe( + "Authors API Suite", + () => { + beforeEach( + ( currentSpec ) => { + // Setup as a new ColdBox request for this suite, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST. + setup(); + } + ); - story( "I want to list all authors", function(){ - given( "no options", function(){ - then( "it can display all active system authors", function(){ - var event = this.get( "/cbapi/v1/authors" ); - expect( event.getResponse() ).toHaveStatus( 200 ); - expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); - event - .getResponse() - .getData() - .each( function( thisItem ){ - expect( thisItem.isActive ).toBeTrue( thisItem.toString() ); - } ); - } ); - } ); - given( "isActive = false", function(){ - then( "it should display inactive users", function(){ - var event = this.get( "/cbapi/v1/authors?isActive=false" ); - expect( event.getResponse() ).toHaveStatus( 200 ); - expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); - event - .getResponse() - .getData() - .each( function( thisItem ){ - expect( thisItem.isActive ).toBeFalse( thisItem.toString() ); - } ); - } ); - } ); - given( "a search criteria", function(){ - then( "it should display searched users", function(){ - var event = this.get( "/cbapi/v1/authors?search=tester" ); - expect( event.getResponse() ).toHaveStatus( 200 ); - expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); - } ); - } ); - } ); // end list all authors + story( + "I want to list all authors", + () => { + given( + "no options", + () => { + then( + "it can display all active system authors", + () => { + var event = this.get( "/cbapi/v1/authors" ); + expect( event.getResponse() ).toHaveStatus( 200 ); + expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); + event + .getResponse() + .getData() + .each( + ( thisItem ) => { + expect( thisItem.isActive ).toBeTrue( thisItem.toString() ); + } + ); + } + ); + } + ); + given( + "isActive = false", + () => { + then( + "it should display inactive users", + () => { + var event = this.get( "/cbapi/v1/authors?isActive=false" ); + expect( event.getResponse() ).toHaveStatus( 200 ); + expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); + event + .getResponse() + .getData() + .each( + ( thisItem ) => { + expect( thisItem.isActive ).toBeFalse( thisItem.toString() ); + } + ); + } + ); + } + ); + given( + "a search criteria", + () => { + then( + "it should display searched users", + () => { + var event = this.get( "/cbapi/v1/authors?search=tester" ); + expect( event.getResponse() ).toHaveStatus( 200 ); + expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); + } + ); + } + ); + } + ); // end list all authors - story( "I want to view an author by id", function(){ - given( "a valid id", function(){ - then( "then I should get the requested author", function(){ - var testUser = variables.authorService.findWhere( { "username" : "lmajano" } ); - var event = this.get( "/cbapi/v1/authors/#testUser.getAuthorID()#" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData().username ).toBe( "lmajano" ); - } ); - } ); - given( "an invalid id or slug", function(){ - then( "then I should see an error message", function(){ - var event = this.get( "/cbapi/v1/authors/123122" ); - expect( event.getResponse() ).toHaveStatus( 404, event.getResponse().getMessagesString() ); - } ); - } ); - } ); // end view author + story( + "I want to view an author by id", + () => { + given( + "a valid id", + () => { + then( + "then I should get the requested author", + () => { + var testUser = variables.authorService.findWhere( { "username": "lmajano" } ); + var event = this.get( "/cbapi/v1/authors/#testUser.getAuthorID()#" ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData().username ).toBe( "lmajano" ); + } + ); + } + ); + given( + "an invalid id or slug", + () => { + then( + "then I should see an error message", + () => { + var event = this.get( "/cbapi/v1/authors/123122" ); + expect( event.getResponse() ).toHaveStatus( 404, + event.getResponse().getMessagesString() ); + } + ); + } + ); + } + ); // end view author - story( "I want to create a new author", function(){ - given( "valid incoming data", function(){ - then( "then I should see the confirmation", function(){ - var testRole = variables.roleService.findWhere( { role : "Administrator" } ); - var testPermission = variables.permissionService.findWhere( { permission : "TOOLS_IMPORT" } ); - withRollback( function(){ - var event = this.post( - "cbapi/v1/authors", - { - firstName : "bdd", - lastName : "bdd", - email : "bdd@ortussolutions.com", - username : "bdd@ortussolutions.com", - role : testRole.getRoleID(), - permissions : testPermission.getPermissionID() - } - ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData().authorID ).notToBeEmpty(); - expect( event.getResponse().getData().username ).toBe( "bdd@ortussolutions.com" ); - } ); - } ); - } ); - given( "duplicate username", function(){ - then( "it should display an error message", function(){ - var testRole = variables.roleService.findWhere( { role : "Administrator" } ); - var testPermission = variables.permissionService.findWhere( { permission : "TOOLS_IMPORT" } ); - var event = this.post( - "cbapi/v1/authors", - { - firstName : "bdd", - lastName : "bdd", - email : "bdd@ortussolutions.com", - username : variables.testAdminUsername, - role : testRole.getRoleID(), - permissions : testPermission.getPermissionID() + story( + "I want to create a new author", + () => { + given( + "valid incoming data", + () => { + then( + "then I should see the confirmation", + () => { + var testRole = variables.roleService.findWhere( { role: "Administrator" } ); + var testPermission = variables.permissionService.findWhere( { + permission: "TOOLS_IMPORT" + } ); + withRollback( + () => { + var event = this.post( + "cbapi/v1/authors", + { + firstName : "bdd", + lastName : "bdd", + email : "bdd@ortussolutions.com", + username : "bdd@ortussolutions.com", + role : testRole.getRoleID(), + permissions: testPermission.getPermissionID() + } + ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData().authorID ).notToBeEmpty(); + expect( event.getResponse().getData().username ).toBe( "bdd@ortussolutions.com" ); + } + ); + } + ); } ); - expect( event.getResponse() ).toHaveStatus( 400, event.getResponse().getMessagesString() ); - expect( event.getResponse() ).toHaveInvalidData( "username", "is not unique" ); - } ); - } ); - given( "duplicate email", function(){ - then( "it should display an error message", function(){ - var testRole = variables.roleService.findWhere( { role : "Administrator" } ); - var testPermission = variables.permissionService.findWhere( { permission : "TOOLS_IMPORT" } ); - var event = this.post( - "cbapi/v1/authors", - { - firstName : "bdd", - lastName : "bdd", - email : variables.testAdminEmail, - username : "uniquebaby!", - role : testRole.getRoleID(), - permissions : testPermission.getPermissionID() + given( + "duplicate username", + () => { + then( + "it should display an error message", + () => { + var testRole = variables.roleService.findWhere( { role: "Administrator" } ); + var testPermission = variables.permissionService.findWhere( { + permission: "TOOLS_IMPORT" + } ); + var event = this.post( + "cbapi/v1/authors", + { + firstName : "bdd", + lastName : "bdd", + email : "bdd@ortussolutions.com", + username : variables.testAdminUsername, + role : testRole.getRoleID(), + permissions: testPermission.getPermissionID() + } + ); + expect( event.getResponse() ).toHaveStatus( 400, + event.getResponse().getMessagesString() ); + expect( event.getResponse() ).toHaveInvalidData( "username", "is not unique" ); + } + ); } ); - expect( event.getResponse() ).toHaveStatus( 400, event.getResponse().getMessagesString() ); - expect( event.getResponse() ).toHaveInvalidData( "email", "is not unique" ); - } ); - } ); - given( "basic invalid data", function(){ - then( "it should display an error message", function(){ - var event = this.post( "cbapi/v1/authors", {} ); - expect( event.getResponse() ).toHaveStatus( 400, event.getResponse().getMessagesString() ); - expect( event.getResponse() ).toHaveInvalidData( "firstName", "is required" ); - expect( event.getResponse() ).toHaveInvalidData( "lastName", "is required" ); - expect( event.getResponse() ).toHaveInvalidData( "email", "is required" ); - expect( event.getResponse() ).toHaveInvalidData( "username", "is required" ); - } ); - } ); - } ); // end create story + given( + "duplicate email", + () => { + then( + "it should display an error message", + () => { + var testRole = variables.roleService.findWhere( { role: "Administrator" } ); + var testPermission = variables.permissionService.findWhere( { + permission: "TOOLS_IMPORT" + } ); + var event = this.post( + "cbapi/v1/authors", + { + firstName : "bdd", + lastName : "bdd", + email : variables.testAdminEmail, + username : "uniquebaby!", + role : testRole.getRoleID(), + permissions: testPermission.getPermissionID() + } + ); + expect( event.getResponse() ).toHaveStatus( 400, + event.getResponse().getMessagesString() ); + expect( event.getResponse() ).toHaveInvalidData( "email", "is not unique" ); + } + ); + } + ); + given( + "basic invalid data", + () => { + then( + "it should display an error message", + () => { + var event = this.post( "cbapi/v1/authors", {} ); + expect( event.getResponse() ).toHaveStatus( 400, + event.getResponse().getMessagesString() ); + expect( event.getResponse() ).toHaveInvalidData( "firstName", "is required" ); + expect( event.getResponse() ).toHaveInvalidData( "lastName", "is required" ); + expect( event.getResponse() ).toHaveInvalidData( "email", "is required" ); + expect( event.getResponse() ).toHaveInvalidData( "username", "is required" ); + } + ); + } + ); + } + ); // end create story - story( "I want to edit an author", function(){ - given( "a valid id and valid data", function(){ - then( "then it should update an author", function(){ - withRollback( function(){ - var testAuthor = variables.authorService.findWhere( { username : "lmajano" } ); - var event = this.put( - "/cbapi/v1/authors/#testAuthor.getAuthorID()#", - { biography : "ColdBox Daddy!" } - ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData().biography ).toInclude( "ColdBox Daddy!" ); - } ); - } ); - } ); - given( "an invalid id or slug", function(){ - then( "then I should see an error message", function(){ - var event = this.put( "/cbapi/v1/authors/1232222" ); - expect( event.getResponse() ).toHaveStatus( 404, event.getResponse().getMessagesString() ); - } ); - } ); - } ); // end edit author + story( + "I want to edit an author", + () => { + given( + "a valid id and valid data", + () => { + then( + "then it should update an author", + () => { + withRollback( + () => { + var testAuthor = variables.authorService.findWhere( { + username: "lmajano" + } ); + var event = this.put( + "/cbapi/v1/authors/#testAuthor.getAuthorID()#", + { biography: "ColdBox Daddy!" } + ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData().biography ).toInclude( "ColdBox Daddy!" ); + } + ); + } + ); + } + ); + given( + "an invalid id or slug", + () => { + then( + "then I should see an error message", + () => { + var event = this.put( "/cbapi/v1/authors/1232222" ); + expect( event.getResponse() ).toHaveStatus( 404, + event.getResponse().getMessagesString() ); + } + ); + } + ); + } + ); // end edit author - story( "I want to delete an author", function(){ - given( "a valid id", function(){ - then( "then I should see the confirmation", function(){ - try { - var testRole = variables.roleService.findWhere( { role : "Administrator" } ); - var testPermission = variables.permissionService.findWhere( { permission : "TOOLS_IMPORT" } ); - var testAuthor = variables.authorService.save( - variables.authorService.new( { - firstName : "bdd", - lastName : "bdd", - email : "bdd@ortussolutions.com", - username : "bddtest", - role : testRole.getRoleID(), - permissions : testPermission.getPermissionID() - } ) - ); - var event = this.delete( "/cbapi/v1/authors/#testAuthor.getAuthorId()#" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getMessagesString() ).toInclude( "deleted" ); - } finally { - queryExecute( - "delete from cb_authorPermissions where FK_authorID = '#testAuthor.getAuthorID()#'" - ); - queryExecute( "delete from cb_author where username = 'bddtest'" ); - } - } ); - } ); - given( "an invalid id or slug", function(){ - then( "then I should see an error message", function(){ - var event = this.delete( "/cbapi/v1/sites/default/categories/1232222" ); - expect( event.getResponse() ).toHaveStatus( 404, event.getResponse().getMessagesString() ); - } ); - } ); - } ); // end delete author - } ); // end describe + story( + "I want to delete an author", + () => { + given( + "a valid id", + () => { + then( + "then I should see the confirmation", + () => { + try { + var testRole = variables.roleService.findWhere( { role: "Administrator" } ); + var testPermission = variables.permissionService.findWhere( { + permission: "TOOLS_IMPORT" + } ); + var testAuthor = variables.authorService.save( + variables.authorService.new( + { + firstName : "bdd", + lastName : "bdd", + email : "bdd@ortussolutions.com", + username : "bddtest", + role : testRole.getRoleID(), + permissions: testPermission.getPermissionID() + } + ) + ); + var event = this.delete( "/cbapi/v1/authors/#testAuthor.getAuthorId()#" ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getMessagesString() ).toInclude( "deleted" ); + } finally { + queryExecute( + "delete from cb_authorPermissions where FK_authorID = '#testAuthor.getAuthorID()#'" + ); + queryExecute( "delete from cb_author where username = 'bddtest'" ); + } + } + ); + } + ); + given( + "an invalid id or slug", + () => { + then( + "then I should see an error message", + () => { + var event = this.delete( "/cbapi/v1/sites/default/categories/1232222" ); + expect( event.getResponse() ).toHaveStatus( 404, + event.getResponse().getMessagesString() ); + } + ); + } + ); + } + ); // end delete author + } + ); // end describe } - // end run -} + + // end run +} \ No newline at end of file diff --git a/tests/specs/contentbox-api/CategoriesSpec.cfc b/tests/specs/contentbox-api/CategoriesSpec.cfc index 5e8bc1fcc1..8f313d63a2 100644 --- a/tests/specs/contentbox-api/CategoriesSpec.cfc +++ b/tests/specs/contentbox-api/CategoriesSpec.cfc @@ -1,6 +1,6 @@ component extends="tests.resources.BaseApiTest" { - property name="siteService" inject="siteService@contentbox"; + property name="categoryService" inject="categoryService@contentbox"; /*********************************** LIFE CYCLE Methods ***********************************/ @@ -8,7 +8,7 @@ component extends="tests.resources.BaseApiTest" { /** * executes before all suites+specs in the run() method */ - function beforeAll(){ + function beforeAll() { super.beforeAll(); // Log in admin variables.loggedInData = loginUser(); @@ -17,143 +17,255 @@ component extends="tests.resources.BaseApiTest" { /** * executes after all suites+specs in the run() method */ - function afterAll(){ + function afterAll() { super.afterAll(); } /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ + function run( testResults, testBox ) { // all your suites go here. - describe( "Site Categories API Suite", function(){ - beforeEach( function( currentSpec ){ - // Setup as a new ColdBox request for this suite, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST. - setup(); - } ); + describe( + "Site Categories API Suite", + () => { + beforeEach( + ( currentSpec ) => { + // Setup as a new ColdBox request for this suite, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST. + setup(); + } + ); - story( "I want to view a category by id or slug", function(){ - given( "a valid id", function(){ - then( "then I should get the requested category", function(){ - var testCategory = variables.categoryService.findWhere( { "slug" : "coldbox", "site" : getDefaultSite() } ); - var event = this.get( "/cbapi/v1/sites/default/categories/#testCategory.getCategoryID()#" ); - expect( event.getResponse() ).toHaveStatus( 200 ); - expect( event.getResponse().getData().slug ).toBe( "coldbox" ); - } ); - } ); - given( "a valid slug", function(){ - then( "then I should get the requested category", function(){ - var event = this.get( "/cbapi/v1/sites/default/categories/coldbox" ); - expect( event.getResponse() ).toHaveStatus( 200 ); - expect( event.getResponse().getData().slug ).toBe( "coldbox" ); - } ); - } ); - given( "an invalid id or slug", function(){ - then( "then I should see an error message", function(){ - var event = this.get( "/cbapi/v1/sites/default/categories/bogus" ); - expect( event.getResponse() ).toHaveStatus( 404 ); - } ); - } ); - } ); // end story view site by id or slug + story( + "I want to view a category by id or slug", + () => { + given( + "a valid id", + () => { + then( + "then I should get the requested category", + () => { + var testCategory = variables.categoryService.findWhere( + { + "slug": "coldbox", + "site": getDefaultSite() + } + ); + var event = this.get( + "/cbapi/v1/sites/default/categories/#testCategory.getCategoryID()#" + ); + expect( event.getResponse() ).toHaveStatus( 200 ); + expect( event.getResponse().getData().slug ).toBe( "coldbox" ); + } + ); + } + ); + given( + "a valid slug", + () => { + then( + "then I should get the requested category", + () => { + var event = this.get( "/cbapi/v1/sites/default/categories/coldbox" ); + expect( event.getResponse() ).toHaveStatus( 200 ); + expect( event.getResponse().getData().slug ).toBe( "coldbox" ); + } + ); + } + ); + given( + "an invalid id or slug", + () => { + then( + "then I should see an error message", + () => { + var event = this.get( "/cbapi/v1/sites/default/categories/bogus" ); + expect( event.getResponse() ).toHaveStatus( 404 ); + } + ); + } + ); + } + ); // end story view site by id or slug - story( "I want to list all site categories", function(){ - given( "no options", function(){ - then( "it can display all site categories", function(){ - var event = this.get( "/cbapi/v1/sites/default/categories" ); - expect( event.getResponse() ).toHaveStatus( 200 ); - expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); - } ); - } ); - } ); // end story list all sites + story( + "I want to list all site categories", + () => { + given( + "no options", + () => { + then( + "it can display all site categories", + () => { + var event = this.get( "/cbapi/v1/sites/default/categories" ); + expect( event.getResponse() ).toHaveStatus( 200 ); + expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); + } + ); + } + ); + } + ); // end story list all sites - story( "I want to create a site category", function(){ - given( "valid incoming data", function(){ - then( "then I should see the confirmation", function(){ - withRollback( function(){ - var event = this.post( - "cbapi/v1/sites/default/categories", - { category : "bddtest", slug : "bddtest" } - ); - expect( event.getResponse() ).toHaveStatus( 200 ); - expect( event.getResponse().getData().categoryID ).notToBeEmpty(); - expect( event.getResponse().getData().slug ).toBe( "bddtest" ); - } ); - } ); - } ); - given( "duplicate category slug", function(){ - then( "it should display an error message", function(){ - var event = this.post( - "cbapi/v1/sites/default/categories", - { category : "coldbox", slug : "coldbox" } + story( + "I want to create a site category", + () => { + given( + "valid incoming data", + () => { + then( + "then I should see the confirmation", + () => { + withRollback( + () => { + var event = this.post( + "cbapi/v1/sites/default/categories", + { category: "bddtest", slug: "bddtest" } + ); + expect( event.getResponse() ).toHaveStatus( 200 ); + expect( event.getResponse().getData().categoryID ).notToBeEmpty(); + expect( event.getResponse().getData().slug ).toBe( "bddtest" ); + } + ); + } + ); + } + ); + given( + "duplicate category slug", + () => { + then( + "it should display an error message", + () => { + var event = this.post( + "cbapi/v1/sites/default/categories", + { category: "coldbox", slug: "coldbox" } + ); + expect( event.getResponse() ).toHaveStatus( 400 ); + expect( event.getResponse() ).toHaveInvalidData( "slug", "is not unique" ); + } + ); + } + ); + given( + "invalid data", + () => { + then( + "it should display an error message", + () => { + var event = this.post( + "cbapi/v1/sites/default/categories", + { name: "A nice category" } + ); + expect( event.getResponse() ).toHaveStatus( 400 ); + expect( event.getResponse() ).toHaveInvalidData( "slug", "is required" ); + } + ); + } ); - expect( event.getResponse() ).toHaveStatus( 400 ); - expect( event.getResponse() ).toHaveInvalidData( "slug", "is not unique" ); - } ); - } ); - given( "invalid data", function(){ - then( "it should display an error message", function(){ - var event = this.post( "cbapi/v1/sites/default/categories", { name : "A nice category" } ); - expect( event.getResponse() ).toHaveStatus( 400 ); - expect( event.getResponse() ).toHaveInvalidData( "slug", "is required" ); - } ); - } ); - } ); // end create story + } + ); // end create story - story( "I want to edit a category", function(){ - given( "a valid id/slug and valid data", function(){ - then( "then it should update a category", function(){ - withRollback( function(){ - var event = this.put( - "/cbapi/v1/sites/default/categories/coldbox", - { category : "ColdBox Rocks" } - ); - expect( event.getResponse() ).toHaveStatus( 200 ); - expect( event.getResponse().getData().category ).toInclude( "ColdBox Rocks" ); - } ); - } ); - } ); - given( "a non-unique slug", function(){ - then( "then I should see a validation message", function(){ - var event = this.put( "/cbapi/v1/sites/default/categories/coldbox", { slug : "coldfusion" } ); - expect( event.getResponse() ).toHaveStatus( 400 ); - expect( event.getResponse() ).toHaveInvalidData( "slug", "is not unique" ); - } ); - } ); - given( "an invalid id or slug", function(){ - then( "then I should see an error message", function(){ - var event = this.put( "/cbapi/v1/sites/categories/123" ); - expect( event.getResponse() ).toHaveStatus( 404 ); - } ); - } ); - } ); // end edit story + story( + "I want to edit a category", + () => { + given( + "a valid id/slug and valid data", + () => { + then( + "then it should update a category", + () => { + withRollback( + () => { + var event = this.put( + "/cbapi/v1/sites/default/categories/coldbox", + { category: "ColdBox Rocks" } + ); + expect( event.getResponse() ).toHaveStatus( 200 ); + expect( event.getResponse().getData().category ).toInclude( "ColdBox Rocks" ); + } + ); + } + ); + } + ); + given( + "a non-unique slug", + () => { + then( + "then I should see a validation message", + () => { + var event = this.put( + "/cbapi/v1/sites/default/categories/coldbox", + { slug: "coldfusion" } + ); + expect( event.getResponse() ).toHaveStatus( 400 ); + expect( event.getResponse() ).toHaveInvalidData( "slug", "is not unique" ); + } + ); + } + ); + given( + "an invalid id or slug", + () => { + then( + "then I should see an error message", + () => { + var event = this.put( "/cbapi/v1/sites/categories/123" ); + expect( event.getResponse() ).toHaveStatus( 404 ); + } + ); + } + ); + } + ); // end edit story - story( "I want to delete a category", function(){ - given( "a valid id/slug", function(){ - then( "then I should see the confirmation", function(){ - try { - var testCategory = variables.categoryService.save( - variables.categoryService.new( { - category : "bddtest", - slug : "bddtest", - site : getDefaultSite() - } ) - ); - var event = this.delete( "/cbapi/v1/sites/default/categories/bddtest" ); - expect( event.getResponse() ).toHaveStatus( 200 ); - expect( event.getResponse().getMessagesString() ).toInclude( "deleted" ); - } finally { - queryExecute( "delete from cb_category where slug = 'bddtest'" ); - } - } ); - } ); - given( "an invalid id or slug", function(){ - then( "then I should see an error message", function(){ - var event = this.delete( "/cbapi/v1/sites/default/categories/1232222" ); - expect( event.getResponse() ).toHaveStatus( 404 ); - } ); - } ); - } ); // end delete story - } ); // end describe + story( + "I want to delete a category", + () => { + given( + "a valid id/slug", + () => { + then( + "then I should see the confirmation", + () => { + try { + var testCategory = variables.categoryService.save( + variables.categoryService.new( + { + category: "bddtest", + slug : "bddtest", + site : getDefaultSite() + } + ) + ); + var event = this.delete( "/cbapi/v1/sites/default/categories/bddtest" ); + expect( event.getResponse() ).toHaveStatus( 200 ); + expect( event.getResponse().getMessagesString() ).toInclude( "deleted" ); + } finally { + queryExecute( "delete from cb_category where slug = 'bddtest'" ); + } + } + ); + } + ); + given( + "an invalid id or slug", + () => { + then( + "then I should see an error message", + () => { + var event = this.delete( "/cbapi/v1/sites/default/categories/1232222" ); + expect( event.getResponse() ).toHaveStatus( 404 ); + } + ); + } + ); + } + ); // end delete story + } + ); // end describe } - // end run -} + + // end run +} \ No newline at end of file diff --git a/tests/specs/contentbox-api/ContentStoreSpec.cfc b/tests/specs/contentbox-api/ContentStoreSpec.cfc index 331e3c2d9f..77993fd6bd 100644 --- a/tests/specs/contentbox-api/ContentStoreSpec.cfc +++ b/tests/specs/contentbox-api/ContentStoreSpec.cfc @@ -1,7 +1,8 @@ component extends="tests.resources.BaseApiTest" { - property name="siteService" inject="siteService@contentbox"; + property name="categoryService" inject="categoryService@contentbox"; + property name="contentStoreService" inject="contentStoreService@contentbox"; /*********************************** LIFE CYCLE Methods ***********************************/ @@ -9,7 +10,7 @@ component extends="tests.resources.BaseApiTest" { /** * executes before all suites+specs in the run() method */ - function beforeAll(){ + function beforeAll() { super.beforeAll(); // Log in admin variables.loggedInData = loginUser(); @@ -18,233 +19,397 @@ component extends="tests.resources.BaseApiTest" { /** * executes after all suites+specs in the run() method */ - function afterAll(){ + function afterAll() { super.afterAll(); } /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ + function run( testResults, testBox ) { // all your suites go here. - describe( "Content Store API Suite", function(){ - beforeEach( function( currentSpec ){ - // Setup as a new ColdBox request for this suite, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST. - setup(); - } ); + describe( + "Content Store API Suite", + () => { + beforeEach( + ( currentSpec ) => { + // Setup as a new ColdBox request for this suite, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST. + setup(); + } + ); - story( "I want to view a content item by id or slug", function(){ - given( "an valid id", function(){ - then( "then I should get the requested content store item", function(){ - var testContent = variables.contentStoreService.findWhere( { slug : "foot" } ); - var event = this.get( "/cbapi/v1/sites/default/contentstore/#testContent.getContentID()#" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData().slug ).toBe( "foot" ); - expect( event.getResponse().getData() ).toHaveKey( - "activeContent,children,customFields,linkedContent,relatedContent,renderedContent" - ); - } ); - } ); - given( "an valid slug", function(){ - then( "then I should get the requested content store item", function(){ - var event = this.get( "/cbapi/v1/sites/default/contentstore/foot" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData().slug ).toBe( "foot" ); - expect( event.getResponse().getData() ).toHaveKey( - "activeContent,children,customFields,linkedContent,relatedContent,renderedContent" - ); - } ); - } ); - given( "an invalid id or slug", function(){ - then( "then I should see an error message", function(){ - var event = this.get( "/cbapi/v1/sites/default/contentstore/123kkdabugosu" ); - expect( event.getResponse() ).toHaveStatus( 404, event.getResponse().getMessagesString() ); - } ); - } ); - } ); // end story view site by id or slug + story( + "I want to view a content item by id or slug", + () => { + given( + "an valid id", + () => { + then( + "then I should get the requested content store item", + () => { + var testContent = variables.contentStoreService.findWhere( { slug: "foot" } ); + var event = this.get( + "/cbapi/v1/sites/default/contentstore/#testContent.getContentID()#" + ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData().slug ).toBe( "foot" ); + expect( event.getResponse().getData() ).toHaveKey( + "activeContent,children,customFields,linkedContent,relatedContent,renderedContent" + ); + } + ); + } + ); + given( + "an valid slug", + () => { + then( + "then I should get the requested content store item", + () => { + var event = this.get( "/cbapi/v1/sites/default/contentstore/foot" ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData().slug ).toBe( "foot" ); + expect( event.getResponse().getData() ).toHaveKey( + "activeContent,children,customFields,linkedContent,relatedContent,renderedContent" + ); + } + ); + } + ); + given( + "an invalid id or slug", + () => { + then( + "then I should see an error message", + () => { + var event = this.get( "/cbapi/v1/sites/default/contentstore/123kkdabugosu" ); + expect( event.getResponse() ).toHaveStatus( 404, + event.getResponse().getMessagesString() ); + } + ); + } + ); + } + ); // end story view site by id or slug - story( "I want to list all content store items", function(){ - given( "no options", function(){ - then( "it can display all items with default filters", function(){ - var event = this.get( "/cbapi/v1/sites/default/contentstore" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); - } ); - } ); - given( "a parent search", function(){ - then( "it can display content store items from a parent", function(){ - var testContent = variables.contentStoreService.findWhere( { slug : "foot" } ); - var event = this.get( - "/cbapi/v1/sites/default/contentstore?parent=#testContent.getContentID()#" - ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - event - .getResponse() - .getData() - .each( function( thisItem ){ - expect( thisItem.parent.slug ).toBe( "foot" ); - } ); - } ); - } ); - given( "a content search", function(){ - then( "it can find the content store item", function(){ - var event = this.get( "/cbapi/v1/sites/default/contentstore?search=foot" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); - } ); - } ); - given( "a slug prefix search", function(){ - then( "it can find the content store items", function(){ - var event = this.get( "/cbapi/v1/sites/default/contentstore?slugPrefix=foot" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); - } ); - } ); - given( "a slug search", function(){ - then( "it can find the content store items", function(){ - var event = this.get( "/cbapi/v1/sites/default/contentstore?slugSearch=foot" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); - } ); - } ); - } ); // end story list all sites + story( + "I want to list all content store items", + () => { + given( + "no options", + () => { + then( + "it can display all items with default filters", + () => { + var event = this.get( "/cbapi/v1/sites/default/contentstore" ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); + } + ); + } + ); + given( + "a parent search", + () => { + then( + "it can display content store items from a parent", + () => { + var testContent = variables.contentStoreService.findWhere( { slug: "foot" } ); + var event = this.get( + "/cbapi/v1/sites/default/contentstore?parent=#testContent.getContentID()#" + ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + event + .getResponse() + .getData() + .each( + ( thisItem ) => { + expect( thisItem.parent.slug ).toBe( "foot" ); + } + ); + } + ); + } + ); + given( + "a content search", + () => { + then( + "it can find the content store item", + () => { + var event = this.get( "/cbapi/v1/sites/default/contentstore?search=foot" ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); + } + ); + } + ); + given( + "a slug prefix search", + () => { + then( + "it can find the content store items", + () => { + var event = this.get( "/cbapi/v1/sites/default/contentstore?slugPrefix=foot" ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); + } + ); + } + ); + given( + "a slug search", + () => { + then( + "it can find the content store items", + () => { + var event = this.get( "/cbapi/v1/sites/default/contentstore?slugSearch=foot" ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); + } + ); + } + ); + } + ); // end story list all sites - story( "I want to create a content store item", function(){ - given( "valid data", function(){ - then( "then it should create a new content object", function(){ - withRollback( function(){ - var event = this.post( - "cbapi/v1/sites/default/contentstore", - { - title : "bddtest", - slug : "bddtest", - description : "my bdd test site", - content : "This is my awesome bdd test content store item", - publishedDate : dateTimeFormat( now(), "yyyy-mm-dd'T'HH:mm:ssZ", "UTC" ), - changelog : "My first creation from the bdd test", - categories : "coldbox,news", - customFields : [ - { key : "test", value : "true" }, - { key : "data", value : "#now()#" } - ] - } - ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - // debug( event.getResponse().getData() ); - expect( event.getResponse().getData().contentID ).notToBeEmpty(); - expect( event.getResponse().getData().slug ).toBe( "bddtest" ); - expect( event.getResponse().getData().categories ).toBeArray().notToBeEmpty(); - expect( event.getResponse().getData().customFields ).toBeStruct().notToBeEmpty(); - } ); - } ); - } ); - given( "duplicate content slug", function(){ - then( "it should display an error message", function(){ - var event = this.post( - "cbapi/v1/sites/default/contentStore", - { - title : "foot", - slug : "foot", - content : "Footer is here", - order : 10 - } - ); - expect( event.getResponse() ).toHaveStatus( 400, event.getResponse().getMessagesString() ); - expect( event.getResponse() ).toHaveInvalidData( "slug", "is not unique" ); - } ); - } ); - given( "invalid content", function(){ - then( "it should display an error message", function(){ - var event = this.post( "cbapi/v1/sites/default/contentStore", { slug : "A nice site" } ); - expect( event.getResponse() ).toHaveStatus( 400, event.getResponse().getMessagesString() ); - // debug( event.getResponse().getMemento() ); + story( + "I want to create a content store item", + () => { + given( + "valid data", + () => { + then( + "then it should create a new content object", + () => { + withRollback( + () => { + var event = this.post( + "cbapi/v1/sites/default/contentstore", + { + title : "bddtest", + slug : "bddtest", + description : "my bdd test site", + content : "This is my awesome bdd test content store item", + publishedDate: dateTimeFormat( + now(), + "yyyy-mm-dd'T'HH:mm:ssZ", + "UTC" + ), + changelog : "My first creation from the bdd test", + categories : "coldbox,news", + customFields: [ + { key: "test", value: "true" }, + { key: "data", value: "#now()#" } + ] + } + ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + // debug( event.getResponse().getData() ); + expect( event.getResponse().getData().contentID ).notToBeEmpty(); + expect( event.getResponse().getData().slug ).toBe( "bddtest" ); + expect( event.getResponse().getData().categories ).toBeArray().notToBeEmpty(); + expect( event.getResponse().getData().customFields ).toBeStruct().notToBeEmpty(); + } + ); + } + ); + } + ); + given( + "duplicate content slug", + () => { + then( + "it should display an error message", + () => { + var event = this.post( + "cbapi/v1/sites/default/contentStore", + { + title : "foot", + slug : "foot", + content: "Footer is here", + order : 10 + } + ); + expect( event.getResponse() ).toHaveStatus( 400, + event.getResponse().getMessagesString() ); + expect( event.getResponse() ).toHaveInvalidData( "slug", "is not unique" ); + } + ); + } + ); + given( + "invalid content", + () => { + then( + "it should display an error message", + () => { + var event = this.post( + "cbapi/v1/sites/default/contentStore", + { slug: "A nice site" } + ); + expect( event.getResponse() ).toHaveStatus( 400, + event.getResponse().getMessagesString() ); + // debug( event.getResponse().getMemento() ); - expect( event.getResponse().getMessages() ).toInclude( "content is required" ); - } ); - } ); - given( "invalid data but good content", function(){ - then( "it should display an error message", function(){ - var event = this.post( - "cbapi/v1/sites/default/contentStore", - { content : "Hello from bdd test land!" } - ); - expect( event.getResponse() ).toHaveStatus( 400, event.getResponse().getMessagesString() ); - expect( event.getResponse() ).toHaveInvalidData( "slug", "is required" ); - expect( event.getResponse() ).toHaveInvalidData( "title", "is required" ); - } ); - } ); - } ); // end create story + expect( event.getResponse().getMessages() ).toInclude( "content is required" ); + } + ); + } + ); + given( + "invalid data but good content", + () => { + then( + "it should display an error message", + () => { + var event = this.post( + "cbapi/v1/sites/default/contentStore", + { content: "Hello from bdd test land!" } + ); + expect( event.getResponse() ).toHaveStatus( 400, + event.getResponse().getMessagesString() ); + expect( event.getResponse() ).toHaveInvalidData( "slug", "is required" ); + expect( event.getResponse() ).toHaveInvalidData( "title", "is required" ); + } + ); + } + ); + } + ); // end create story - story( "I want to edit a content store item", function(){ - given( "a valid id/slug and valid data", function(){ - then( "then it should update a content item", function(){ - getCache( "template" ).clearAll(); - withRollback( function(){ - var event = this.put( - "/cbapi/v1/sites/default/contentstore/foot", - { - content : "I am a new piece of content for the footer!", - changelog : "Update from a bdd test!" - } - ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData().renderedContent ).toInclude( - "I am a new piece of content for the footer!" - ); - expect( event.getResponse().getData().activeContent.changelog ).toInclude( "bdd test" ); - } ); - } ); - } ); - given( "duplicate content slug", function(){ - then( "it should display an error message", function(){ - var event = this.put( - "cbapi/v1/sites/default/contentStore/foot", - { - title : "foot", - slug : "my-awesome-news", - content : "Footer is here" - } - ); - expect( event.getResponse() ).toHaveStatus( 400, event.getResponse().getMessagesString() ); - expect( event.getResponse() ).toHaveInvalidData( "slug", "is not unique" ); - } ); - } ); - given( "an invalid id or slug", function(){ - then( "then I should see an error message", function(){ - var event = this.put( "/cbapi/v1/sites/default/contentstore/bogusbaby", { content : "bogus" } ); - expect( event.getResponse() ).toHaveStatus( 404, event.getResponse().getMessagesString() ); - } ); - } ); - } ); // end edit story + story( + "I want to edit a content store item", + () => { + given( + "a valid id/slug and valid data", + () => { + then( + "then it should update a content item", + () => { + getCache( "template" ).clearAll(); + withRollback( + () => { + var event = this.put( + "/cbapi/v1/sites/default/contentstore/foot", + { + content : "I am a new piece of content for the footer!", + changelog: "Update from a bdd test!" + } + ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData().renderedContent ).toInclude( "I am a new piece of content for the footer!" ); + expect( event.getResponse().getData().activeContent.changelog ).toInclude( "bdd test" ); + } + ); + } + ); + } + ); + given( + "duplicate content slug", + () => { + then( + "it should display an error message", + () => { + var event = this.put( + "cbapi/v1/sites/default/contentStore/foot", + { + title : "foot", + slug : "my-awesome-news", + content: "Footer is here" + } + ); + expect( event.getResponse() ).toHaveStatus( 400, + event.getResponse().getMessagesString() ); + expect( event.getResponse() ).toHaveInvalidData( "slug", "is not unique" ); + } + ); + } + ); + given( + "an invalid id or slug", + () => { + then( + "then I should see an error message", + () => { + var event = this.put( + "/cbapi/v1/sites/default/contentstore/bogusbaby", + { content: "bogus" } + ); + expect( event.getResponse() ).toHaveStatus( 404, + event.getResponse().getMessagesString() ); + } + ); + } + ); + } + ); // end edit story - story( "I want to delete a content store item", function(){ - given( "a valid id/slug", function(){ - then( "then I should see the confirmation", function(){ - var testContent = variables.contentstoreService.save( - variables.contentstoreService.new( { - title : "bddtest", - slug : "bddtest", - description : "my bdd test site", - content : "This is my awesome bdd test content store item", - publishedDate : dateTimeFormat( now(), "yyyy-mm-dd'T'HH:mm:ssZ", "UTC" ), - changelog : "My first creation from the bdd test", - site : variables.siteService.getDefaultSite(), - creator : variables.loggedInData.user - } ) - ); - var event = this.delete( "/cbapi/v1/sites/default/contentstore/#testContent.getContentID()#" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getMessagesString() ).toInclude( "deleted" ); - } ); - } ); - given( "an invalid id or slug", function(){ - then( "then I should see an error message", function(){ - var event = this.delete( "/cbapi/v1/sites/default/contentstore/bogusbogus" ); - expect( event.getResponse() ).toHaveStatus( 404, event.getResponse().getMessagesString() ); - } ); - } ); - } ); // end delete story - } ); // end describe + story( + "I want to delete a content store item", + () => { + given( + "a valid id/slug", + () => { + then( + "then I should see the confirmation", + () => { + var testContent = variables.contentstoreService.save( + variables.contentstoreService.new( + { + title : "bddtest", + slug : "bddtest", + description : "my bdd test site", + content : "This is my awesome bdd test content store item", + publishedDate: dateTimeFormat( + now(), + "yyyy-mm-dd'T'HH:mm:ssZ", + "UTC" + ), + changelog: "My first creation from the bdd test", + site : variables.siteService.getDefaultSite(), + creator : variables.loggedInData.user + } + ) + ); + var event = this.delete( + "/cbapi/v1/sites/default/contentstore/#testContent.getContentID()#" + ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getMessagesString() ).toInclude( "deleted" ); + } + ); + } + ); + given( + "an invalid id or slug", + () => { + then( + "then I should see an error message", + () => { + var event = this.delete( "/cbapi/v1/sites/default/contentstore/bogusbogus" ); + expect( event.getResponse() ).toHaveStatus( 404, + event.getResponse().getMessagesString() ); + } + ); + } + ); + } + ); // end delete story + } + ); // end describe } - // end run -} + + // end run +} \ No newline at end of file diff --git a/tests/specs/contentbox-api/EchoSpec.cfc b/tests/specs/contentbox-api/EchoSpec.cfc index 6d9b278f87..341455dd7d 100644 --- a/tests/specs/contentbox-api/EchoSpec.cfc +++ b/tests/specs/contentbox-api/EchoSpec.cfc @@ -1,69 +1,88 @@ -component extends="tests.resources.BaseApiTest" { +component extends="tests.resources.BaseApiTest" { /*********************************** LIFE CYCLE Methods ***********************************/ - function beforeAll(){ + function beforeAll() { super.beforeAll(); + + // do your own stuff here } - function afterAll(){ + function afterAll() { // do your own stuff here super.afterAll(); } /*********************************** BDD SUITES ***********************************/ - function run(){ - describe( "My ContentBox RESTFUl Service", function(){ - beforeEach( function( currentSpec ){ - // Setup as a new ColdBox request, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST. - setup(); - } ); - - it( "can handle invalid HTTP Calls", function(){ - var event = execute( - event = "contentbox-api-v1:echo.onInvalidHTTPMethod", - renderResults = true, - eventArguments = { faultAction : "test" } + function run() { + describe( + "My ContentBox RESTFUl Service", + () => { + beforeEach( + ( currentSpec ) => { + // Setup as a new ColdBox request, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST. + setup(); + } ); - var response = event.getPrivateValue( "response" ); - expect( response.getError() ).toBeTrue(); - expect( response.getStatusCode() ).toBe( 405 ); - } ); - it( "can handle global exceptions", function(){ - var event = execute( - event = "contentbox-api-v1:echo.onError", - renderResults = true, - eventArguments = { - exception : { - message : "unit test", - detail : "unit test", - stacktrace : "" - } + it( + "can handle invalid HTTP Calls", + () => { + var event = execute( + event = "contentbox-api-v1:echo.onInvalidHTTPMethod", + renderResults = true, + eventArguments = { faultAction: "test" } + ); + var response = event.getPrivateValue( "response" ); + expect( response.getError() ).toBeTrue(); + expect( response.getStatusCode() ).toBe( 405 ); } ); - var response = event.getPrivateValue( "response" ); - expect( response.getError() ).toBeTrue(); - expect( response.getStatusCode() ).toBe( 500 ); - } ); + it( + "can handle global exceptions", + () => { + var event = execute( + event = "contentbox-api-v1:echo.onError", + renderResults = true, + eventArguments = { + exception: { + message : "unit test", + detail : "unit test", + stacktrace: "" + } + } + ); - it( "can handle an echo", function(){ - var event = this.request( "/cbapi/v1" ); - var response = event.getPrivateValue( "response" ); - expect( response.getError() ).toBeFalse(); - expect( response.getData() ).toBe( "Welcome to the ContentBox API v1.x Services" ); - } ); + var response = event.getPrivateValue( "response" ); + expect( response.getError() ).toBeTrue(); + expect( response.getStatusCode() ).toBe( 500 ); + } + ); - it( "can handle missing actions", function(){ - var event = this.request( "/cbapi/v1/echo/bogus" ); - var response = event.getPrivateValue( "response" ); - expect( response.getError() ).tobeTrue(); - expect( response.getStatusCode() ).toBe( 404 ); - } ); - } ); + it( + "can handle an echo", + () => { + var event = this.request( "/cbapi/v1" ); + var response = event.getPrivateValue( "response" ); + expect( response.getError() ).toBeFalse(); + expect( response.getData() ).toBe( "Welcome to the ContentBox API v1.x Services" ); + } + ); + + it( + "can handle missing actions", + () => { + var event = this.request( "/cbapi/v1/echo/bogus" ); + var response = event.getPrivateValue( "response" ); + expect( response.getError() ).tobeTrue(); + expect( response.getStatusCode() ).toBe( 404 ); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-api/EntriesSpec.cfc b/tests/specs/contentbox-api/EntriesSpec.cfc index bc79c5228b..1640ba2d16 100644 --- a/tests/specs/contentbox-api/EntriesSpec.cfc +++ b/tests/specs/contentbox-api/EntriesSpec.cfc @@ -1,7 +1,8 @@ component extends="tests.resources.BaseApiTest" { - property name="siteService" inject="siteService@contentbox"; + property name="categoryService" inject="categoryService@contentbox"; + property name="entryService" inject="entryService@contentbox"; /*********************************** LIFE CYCLE Methods ***********************************/ @@ -9,7 +10,7 @@ component extends="tests.resources.BaseApiTest" { /** * executes before all suites+specs in the run() method */ - function beforeAll(){ + function beforeAll() { super.beforeAll(); // Log in admin variables.loggedInData = loginUser(); @@ -18,211 +19,361 @@ component extends="tests.resources.BaseApiTest" { /** * executes after all suites+specs in the run() method */ - function afterAll(){ + function afterAll() { super.afterAll(); } /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ + function run( testResults, testBox ) { // all your suites go here. - describe( "Entries API Suite", function(){ - beforeEach( function( currentSpec ){ - // Setup as a new ColdBox request for this suite, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST. - setup(); - } ); + describe( + "Entries API Suite", + () => { + beforeEach( + ( currentSpec ) => { + // Setup as a new ColdBox request for this suite, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST. + setup(); + } + ); - story( "I want to view an entry item by id or slug", function(){ - given( "an valid id", function(){ - then( "then I should get the requested entry", function(){ - var testContent = variables.entryService.findWhere( { slug : "disk-queues-77caf" } ); - var event = this.get( "/cbapi/v1/sites/default/entries/#testContent.getContentID()#" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData().slug ).toBe( "disk-queues-77caf" ); - expect( event.getResponse().getData() ).toHaveKey( - "activeContent,children,customFields,linkedContent,relatedContent,renderedContent" + story( + "I want to view an entry item by id or slug", + () => { + given( + "an valid id", + () => { + then( + "then I should get the requested entry", + () => { + var testContent = variables.entryService.findWhere( { + slug: "disk-queues-77caf" + } ); + var event = this.get( + "/cbapi/v1/sites/default/entries/#testContent.getContentID()#" + ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData().slug ).toBe( "disk-queues-77caf" ); + expect( event.getResponse().getData() ).toHaveKey( + "activeContent,children,customFields,linkedContent,relatedContent,renderedContent" + ); + } + ); + } ); - } ); - } ); - given( "a valid slug", function(){ - then( "then I should get the requested entry", function(){ - var event = this.get( "/cbapi/v1/sites/default/entries/disk-queues-77caf" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData().slug ).toBe( "disk-queues-77caf" ); - expect( event.getResponse().getData() ).toHaveKey( - "activeContent,children,customFields,linkedContent,relatedContent,renderedContent" + given( + "a valid slug", + () => { + then( + "then I should get the requested entry", + () => { + var event = this.get( "/cbapi/v1/sites/default/entries/disk-queues-77caf" ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData().slug ).toBe( "disk-queues-77caf" ); + expect( event.getResponse().getData() ).toHaveKey( + "activeContent,children,customFields,linkedContent,relatedContent,renderedContent" + ); + } + ); + } + ); + given( + "an invalid id or slug", + () => { + then( + "then I should see an error message", + () => { + var event = this.get( "/cbapi/v1/sites/default/entries/123kkdabugosu" ); + expect( event.getResponse() ).toHaveStatus( 404, + event.getResponse().getMessagesString() ); + } + ); + } ); - } ); - } ); - given( "an invalid id or slug", function(){ - then( "then I should see an error message", function(){ - var event = this.get( "/cbapi/v1/sites/default/entries/123kkdabugosu" ); - expect( event.getResponse() ).toHaveStatus( 404, event.getResponse().getMessagesString() ); - } ); - } ); - } ); // end story view site by id or slug + } + ); // end story view site by id or slug - story( "I want to list all entries", function(){ - given( "no options", function(){ - then( "it can display all items with default filters", function(){ - var event = this.get( "/cbapi/v1/sites/default/entries" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); - } ); - } ); - given( "a content search", function(){ - then( "it can find the entries", function(){ - var event = this.get( "/cbapi/v1/sites/default/entries?search=disk-queues" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); - } ); - } ); - given( "a slug search", function(){ - then( "it can find the entries", function(){ - var event = this.get( "/cbapi/v1/sites/default/entries?slugSearch=disk-queues-77caf" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); - } ); - } ); - } ); // end story list all sites + story( + "I want to list all entries", + () => { + given( + "no options", + () => { + then( + "it can display all items with default filters", + () => { + var event = this.get( "/cbapi/v1/sites/default/entries" ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); + } + ); + } + ); + given( + "a content search", + () => { + then( + "it can find the entries", + () => { + var event = this.get( "/cbapi/v1/sites/default/entries?search=disk-queues" ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); + } + ); + } + ); + given( + "a slug search", + () => { + then( + "it can find the entries", + () => { + var event = this.get( + "/cbapi/v1/sites/default/entries?slugSearch=disk-queues-77caf" + ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); + } + ); + } + ); + } + ); // end story list all sites - story( "I want to create an entry", function(){ - given( "valid data", function(){ - then( "then it should create a new content object", function(){ - withRollback( function(){ - var event = this.post( - "cbapi/v1/sites/default/entries", - { - title : "bddtest", - slug : "bddtest", - excerpt : "bdd rules!", - content : "This is my awesome bdd test entry", - publishedDate : dateTimeFormat( now(), "yyyy-mm-dd'T'HH:mm:ssZ", "UTC" ), - changelog : "My first creation from the bdd test", - categories : "coldbox,news", - customFields : [ - { key : "test", value : "true" }, - { key : "data", value : "#now()#" } - ] - } - ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - // debug( event.getResponse().getData() ); - expect( event.getResponse().getData().contentID ).notToBeEmpty(); - expect( event.getResponse().getData().slug ).toBe( "bddtest" ); - expect( event.getResponse().getData().excerpt ).toInclude( "bdd" ); - expect( event.getResponse().getData().categories ).toBeArray().notToBeEmpty(); - expect( event.getResponse().getData().customFields ).toBeStruct().notToBeEmpty(); - } ); - } ); - } ); - given( "duplicate content slug", function(){ - then( "it should display an error message", function(){ - var event = this.post( - "cbapi/v1/sites/default/entries", - { - title : "disk-queues-77caf", - slug : "disk-queues-77caf", - content : "disk-queues-77caf are here", - order : 10 + story( + "I want to create an entry", + () => { + given( + "valid data", + () => { + then( + "then it should create a new content object", + () => { + withRollback( + () => { + var event = this.post( + "cbapi/v1/sites/default/entries", + { + title : "bddtest", + slug : "bddtest", + excerpt : "bdd rules!", + content : "This is my awesome bdd test entry", + publishedDate: dateTimeFormat( + now(), + "yyyy-mm-dd'T'HH:mm:ssZ", + "UTC" + ), + changelog : "My first creation from the bdd test", + categories : "coldbox,news", + customFields: [ + { key: "test", value: "true" }, + { key: "data", value: "#now()#" } + ] + } + ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + // debug( event.getResponse().getData() ); + expect( event.getResponse().getData().contentID ).notToBeEmpty(); + expect( event.getResponse().getData().slug ).toBe( "bddtest" ); + expect( event.getResponse().getData().excerpt ).toInclude( "bdd" ); + expect( event.getResponse().getData().categories ).toBeArray().notToBeEmpty(); + expect( event.getResponse().getData().customFields ).toBeStruct().notToBeEmpty(); + } + ); + } + ); + } + ); + given( + "duplicate content slug", + () => { + then( + "it should display an error message", + () => { + var event = this.post( + "cbapi/v1/sites/default/entries", + { + title : "disk-queues-77caf", + slug : "disk-queues-77caf", + content: "disk-queues-77caf are here", + order : 10 + } + ); + expect( event.getResponse() ).toHaveStatus( 400, + event.getResponse().getMessagesString() ); + expect( event.getResponse() ).toHaveInvalidData( "slug", "is not unique" ); + } + ); } ); - expect( event.getResponse() ).toHaveStatus( 400, event.getResponse().getMessagesString() ); - expect( event.getResponse() ).toHaveInvalidData( "slug", "is not unique" ); - } ); - } ); - given( "no content on a new content object", function(){ - then( "it should display an error message", function(){ - var event = this.post( "cbapi/v1/sites/default/entries", { slug : "A nice site" } ); - expect( event.getResponse() ).toHaveStatus( 400, event.getResponse().getMessagesString() ); - // debug( event.getResponse().getMemento() ); + given( + "no content on a new content object", + () => { + then( + "it should display an error message", + () => { + var event = this.post( "cbapi/v1/sites/default/entries", + { slug: "A nice site" } ); + expect( event.getResponse() ).toHaveStatus( 400, + event.getResponse().getMessagesString() ); + // debug( event.getResponse().getMemento() ); - expect( event.getResponse().getMessages() ).toInclude( "content is required" ); - } ); - } ); - given( "invalid data but good content", function(){ - then( "it should display an error message", function(){ - var event = this.post( - "cbapi/v1/sites/default/entries", - { content : "Hello from bdd test land!" } + expect( event.getResponse().getMessages() ).toInclude( "content is required" ); + } + ); + } + ); + given( + "invalid data but good content", + () => { + then( + "it should display an error message", + () => { + var event = this.post( + "cbapi/v1/sites/default/entries", + { content: "Hello from bdd test land!" } + ); + expect( event.getResponse() ).toHaveStatus( 400, + event.getResponse().getMessagesString() ); + expect( event.getResponse() ).toHaveInvalidData( "slug", "is required" ); + expect( event.getResponse() ).toHaveInvalidData( "title", "is required" ); + } + ); + } ); - expect( event.getResponse() ).toHaveStatus( 400, event.getResponse().getMessagesString() ); - expect( event.getResponse() ).toHaveInvalidData( "slug", "is required" ); - expect( event.getResponse() ).toHaveInvalidData( "title", "is required" ); - } ); - } ); - } ); // end create story + } + ); // end create story - story( "I want to edit an entry", function(){ - given( "a valid id/slug and valid data", function(){ - then( "then it should update a content item", function(){ - getCache( "template" ).clearAll(); - withRollback( function(){ - var event = this.put( - "/cbapi/v1/sites/default/entries/disk-queues-77caf", - { - content : "I am a new piece of content for the disk-queues-77caf!", - changelog : "Update from a bdd test!" - } - ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData().renderedContent ).toInclude( - "I am a new piece of content for the disk-queues-77caf!" - ); - expect( event.getResponse().getData().activeContent.changelog ).toInclude( "bdd test" ); - } ); - } ); - } ); - given( "duplicate content slug", function(){ - then( "it should display an error message", function(){ - var event = this.put( - "cbapi/v1/sites/default/entries/disk-queues-77caf", - { - title : "this-is-just-awesome", - slug : "this-is-just-awesome", - content : "disk-queues-77caf are here" + story( + "I want to edit an entry", + () => { + given( + "a valid id/slug and valid data", + () => { + then( + "then it should update a content item", + () => { + getCache( "template" ).clearAll(); + withRollback( + () => { + var event = this.put( + "/cbapi/v1/sites/default/entries/disk-queues-77caf", + { + content : "I am a new piece of content for the disk-queues-77caf!", + changelog: "Update from a bdd test!" + } + ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData().renderedContent ).toInclude( "I am a new piece of content for the disk-queues-77caf!" ); + expect( event.getResponse().getData().activeContent.changelog ).toInclude( "bdd test" ); + } + ); + } + ); + } + ); + given( + "duplicate content slug", + () => { + then( + "it should display an error message", + () => { + var event = this.put( + "cbapi/v1/sites/default/entries/disk-queues-77caf", + { + title : "this-is-just-awesome", + slug : "this-is-just-awesome", + content: "disk-queues-77caf are here" + } + ); + expect( event.getResponse() ).toHaveStatus( 400, + event.getResponse().getMessagesString() ); + expect( event.getResponse() ).toHaveInvalidData( "slug", "is not unique" ); + } + ); + } + ); + given( + "an invalid id or slug", + () => { + then( + "then I should see an error message", + () => { + var event = this.put( + "/cbapi/v1/sites/default/entries/bogusbaby", + { content: "bogus" } + ); + expect( event.getResponse() ).toHaveStatus( 404, + event.getResponse().getMessagesString() ); + } + ); } ); - expect( event.getResponse() ).toHaveStatus( 400, event.getResponse().getMessagesString() ); - expect( event.getResponse() ).toHaveInvalidData( "slug", "is not unique" ); - } ); - } ); - given( "an invalid id or slug", function(){ - then( "then I should see an error message", function(){ - var event = this.put( "/cbapi/v1/sites/default/entries/bogusbaby", { content : "bogus" } ); - expect( event.getResponse() ).toHaveStatus( 404, event.getResponse().getMessagesString() ); - } ); - } ); - } ); // end edit story + } + ); // end edit story - story( "I want to delete a entry", function(){ - given( "a valid id/slug", function(){ - then( "then I should see the confirmation", function(){ - var testContent = variables.entryService.save( - variables.entryService.new( { - title : "bddtest", - slug : "bddtest", - content : "This is my awesome bdd test entry", - publishedDate : dateTimeFormat( now(), "yyyy-mm-dd'T'HH:mm:ssZ", "UTC" ), - changelog : "My first creation from the bdd test", - site : variables.siteService.getDefaultSite(), - creator : variables.loggedInData.user - } ) + story( + "I want to delete a entry", + () => { + given( + "a valid id/slug", + () => { + then( + "then I should see the confirmation", + () => { + var testContent = variables.entryService.save( + variables.entryService.new( + { + title : "bddtest", + slug : "bddtest", + content : "This is my awesome bdd test entry", + publishedDate: dateTimeFormat( + now(), + "yyyy-mm-dd'T'HH:mm:ssZ", + "UTC" + ), + changelog: "My first creation from the bdd test", + site : variables.siteService.getDefaultSite(), + creator : variables.loggedInData.user + } + ) + ); + var event = this.delete( + "/cbapi/v1/sites/default/entries/#testContent.getContentID()#" + ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getMessagesString() ).toInclude( "deleted" ); + } + ); + } + ); + given( + "an invalid id or slug", + () => { + then( + "then I should see an error message", + () => { + var event = this.delete( "/cbapi/v1/sites/default/entries/bogusbogus" ); + expect( event.getResponse() ).toHaveStatus( 404, + event.getResponse().getMessagesString() ); + } + ); + } ); - var event = this.delete( "/cbapi/v1/sites/default/entries/#testContent.getContentID()#" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getMessagesString() ).toInclude( "deleted" ); - } ); - } ); - given( "an invalid id or slug", function(){ - then( "then I should see an error message", function(){ - var event = this.delete( "/cbapi/v1/sites/default/entries/bogusbogus" ); - expect( event.getResponse() ).toHaveStatus( 404, event.getResponse().getMessagesString() ); - } ); - } ); - } ); // end delete story - } ); // end describe + } + ); // end delete story + } + ); // end describe } - // end run -} + + // end run +} \ No newline at end of file diff --git a/tests/specs/contentbox-api/PagesSpec.cfc b/tests/specs/contentbox-api/PagesSpec.cfc index 9f438df2f6..c576088889 100644 --- a/tests/specs/contentbox-api/PagesSpec.cfc +++ b/tests/specs/contentbox-api/PagesSpec.cfc @@ -1,7 +1,8 @@ component extends="tests.resources.BaseApiTest" { - property name="siteService" inject="siteService@contentbox"; + property name="categoryService" inject="categoryService@contentbox"; + property name="pageService" inject="pageService@contentbox"; /*********************************** LIFE CYCLE Methods ***********************************/ @@ -9,7 +10,7 @@ component extends="tests.resources.BaseApiTest" { /** * executes before all suites+specs in the run() method */ - function beforeAll(){ + function beforeAll() { super.beforeAll(); // Log in admin variables.loggedInData = loginUser(); @@ -18,243 +19,414 @@ component extends="tests.resources.BaseApiTest" { /** * executes after all suites+specs in the run() method */ - function afterAll(){ + function afterAll() { super.afterAll(); } /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ + function run( testResults, testBox ) { // all your suites go here. - describe( "Pages API Suite", function(){ - beforeEach( function( currentSpec ){ - // Setup as a new ColdBox request for this suite, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST. - setup(); - } ); + describe( + "Pages API Suite", + () => { + beforeEach( + ( currentSpec ) => { + // Setup as a new ColdBox request for this suite, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST. + setup(); + } + ); - story( "I want to view a page item by id or slug", function(){ - given( "a valid id", function(){ - then( "then I should get the requested page", function(){ - var testContent = variables.pageService.findWhere( { slug : "products" } ); - var event = this.get( "/cbapi/v1/sites/default/pages/#testContent.getContentID()#" ); - // debug( event.getResponse().getData() ) - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData().slug ).toBe( "products" ); - expect( event.getResponse().getData() ).toHaveKey( - "activeContent,children,customFields,linkedContent,relatedContent,renderedContent" + story( + "I want to view a page item by id or slug", + () => { + given( + "a valid id", + () => { + then( + "then I should get the requested page", + () => { + var testContent = variables.pageService.findWhere( { slug: "products" } ); + var event = this.get( + "/cbapi/v1/sites/default/pages/#testContent.getContentID()#" + ); + // debug( event.getResponse().getData() ) + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData().slug ).toBe( "products" ); + expect( event.getResponse().getData() ).toHaveKey( + "activeContent,children,customFields,linkedContent,relatedContent,renderedContent" + ); + } + ); + } ); - } ); - } ); - given( "a valid slug", function(){ - then( "then I should get the requested page", function(){ - var event = this.get( "/cbapi/v1/sites/default/pages/products" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData().slug ).toBe( "products" ); - expect( event.getResponse().getData() ).toHaveKey( - "activeContent,children,customFields,linkedContent,relatedContent,renderedContent" + given( + "a valid slug", + () => { + then( + "then I should get the requested page", + () => { + var event = this.get( "/cbapi/v1/sites/default/pages/products" ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData().slug ).toBe( "products" ); + expect( event.getResponse().getData() ).toHaveKey( + "activeContent,children,customFields,linkedContent,relatedContent,renderedContent" + ); + } + ); + } ); - } ); - } ); - given( "an invalid id or slug", function(){ - then( "then I should see an error message", function(){ - var event = this.get( "/cbapi/v1/sites/default/pages/123kkdabugosu" ); - expect( event.getResponse() ).toHaveStatus( 404, event.getResponse().getMessagesString() ); - } ); - } ); - } ); // end story view site by id or slug + given( + "an invalid id or slug", + () => { + then( + "then I should see an error message", + () => { + var event = this.get( "/cbapi/v1/sites/default/pages/123kkdabugosu" ); + expect( event.getResponse() ).toHaveStatus( 404, + event.getResponse().getMessagesString() ); + } + ); + } + ); + } + ); // end story view site by id or slug - story( "I want to list all pages", function(){ - given( "no options", function(){ - then( "it can display all items with default filters", function(){ - var event = this.get( "/cbapi/v1/sites/default/pages" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); - } ); - } ); - given( "a parent search", function(){ - then( "it can display pages from a parent", function(){ - var testContent = variables.pageService.findWhere( { slug : "products" } ); - var event = this.get( "/cbapi/v1/sites/default/pages?parent=#testContent.getContentID()#" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - event - .getResponse() - .getData() - .each( function( thisItem ){ - expect( thisItem.parent.slug ).toBe( "products" ); - } ); - } ); - } ); - given( "a content search", function(){ - then( "it can find the page", function(){ - var event = this.get( "/cbapi/v1/sites/default/pages?search=products" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); - } ); - } ); - given( "a slug prefix search", function(){ - then( "it can find the pages", function(){ - var event = this.get( "/cbapi/v1/sites/default/pages?slugPrefix=products" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); - } ); - } ); - given( "a slug search", function(){ - then( "it can find the pages", function(){ - var event = this.get( "/cbapi/v1/sites/default/pages?slugSearch=products" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); - } ); - } ); - given( "a show on menu search", function(){ - then( "it can find pages with showInMenu = false", function(){ - var event = this.get( "/cbapi/v1/sites/default/pages?showInMenu=false" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData() ).toBeArray().toBeEmpty(); - } ); - } ); - } ); // end story list all sites + story( + "I want to list all pages", + () => { + given( + "no options", + () => { + then( + "it can display all items with default filters", + () => { + var event = this.get( "/cbapi/v1/sites/default/pages" ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); + } + ); + } + ); + given( + "a parent search", + () => { + then( + "it can display pages from a parent", + () => { + var testContent = variables.pageService.findWhere( { slug: "products" } ); + var event = this.get( + "/cbapi/v1/sites/default/pages?parent=#testContent.getContentID()#" + ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + event + .getResponse() + .getData() + .each( + ( thisItem ) => { + expect( thisItem.parent.slug ).toBe( "products" ); + } + ); + } + ); + } + ); + given( + "a content search", + () => { + then( + "it can find the page", + () => { + var event = this.get( "/cbapi/v1/sites/default/pages?search=products" ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); + } + ); + } + ); + given( + "a slug prefix search", + () => { + then( + "it can find the pages", + () => { + var event = this.get( "/cbapi/v1/sites/default/pages?slugPrefix=products" ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); + } + ); + } + ); + given( + "a slug search", + () => { + then( + "it can find the pages", + () => { + var event = this.get( "/cbapi/v1/sites/default/pages?slugSearch=products" ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); + } + ); + } + ); + given( + "a show on menu search", + () => { + then( + "it can find pages with showInMenu = false", + () => { + var event = this.get( "/cbapi/v1/sites/default/pages?showInMenu=false" ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData() ).toBeArray().toBeEmpty(); + } + ); + } + ); + } + ); // end story list all sites - story( "I want to create a page", function(){ - given( "valid data", function(){ - then( "then it should create a new content object", function(){ - withRollback( function(){ - var event = this.post( - "cbapi/v1/sites/default/pages", - { - title : "bddtest", - slug : "bddtest", - excerpt : "bdd rules!", - content : "This is my awesome bdd test page", - publishedDate : dateTimeFormat( now(), "yyyy-mm-dd'T'HH:mm:ssZ", "UTC" ), - layout : "pages", - showInMenu : "false", - changelog : "My first creation from the bdd test", - categories : "coldbox,news", - customFields : [ - { key : "test", value : "true" }, - { key : "data", value : "#now()#" } - ] - } - ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - // debug( event.getResponse().getData() ); - expect( event.getResponse().getData().contentID ).notToBeEmpty(); - expect( event.getResponse().getData().slug ).toBe( "bddtest" ); - expect( event.getResponse().getData().excerpt ).toInclude( "bdd" ); - expect( event.getResponse().getData().showInMenu ).toBeFalse(); - expect( event.getResponse().getData().layout ).toBe( "pages" ); - expect( event.getResponse().getData().categories ).toBeArray().notToBeEmpty(); - expect( event.getResponse().getData().customFields ).toBeStruct().notToBeEmpty(); - } ); - } ); - } ); - given( "duplicate content slug", function(){ - then( "it should display an error message", function(){ - var event = this.post( - "cbapi/v1/sites/default/pages", - { - title : "products", - slug : "products", - content : "Products are here", - order : 10 + story( + "I want to create a page", + () => { + given( + "valid data", + () => { + then( + "then it should create a new content object", + () => { + withRollback( + () => { + var event = this.post( + "cbapi/v1/sites/default/pages", + { + title : "bddtest", + slug : "bddtest", + excerpt : "bdd rules!", + content : "This is my awesome bdd test page", + publishedDate: dateTimeFormat( + now(), + "yyyy-mm-dd'T'HH:mm:ssZ", + "UTC" + ), + layout : "pages", + showInMenu : "false", + changelog : "My first creation from the bdd test", + categories : "coldbox,news", + customFields: [ + { key: "test", value: "true" }, + { key: "data", value: "#now()#" } + ] + } + ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + // debug( event.getResponse().getData() ); + expect( event.getResponse().getData().contentID ).notToBeEmpty(); + expect( event.getResponse().getData().slug ).toBe( "bddtest" ); + expect( event.getResponse().getData().excerpt ).toInclude( "bdd" ); + expect( event.getResponse().getData().showInMenu ).toBeFalse(); + expect( event.getResponse().getData().layout ).toBe( "pages" ); + expect( event.getResponse().getData().categories ).toBeArray().notToBeEmpty(); + expect( event.getResponse().getData().customFields ).toBeStruct().notToBeEmpty(); + } + ); + } + ); } ); - expect( event.getResponse() ).toHaveStatus( 400, event.getResponse().getMessagesString() ); - expect( event.getResponse() ).toHaveInvalidData( "slug", "is not unique" ); - } ); - } ); - given( "no content on a new content object", function(){ - then( "it should display an error message", function(){ - var event = this.post( "cbapi/v1/sites/default/pages", { slug : "A nice site" } ); - expect( event.getResponse() ).toHaveStatus( 400, event.getResponse().getMessagesString() ); - // debug( event.getResponse().getMemento() ); + given( + "duplicate content slug", + () => { + then( + "it should display an error message", + () => { + var event = this.post( + "cbapi/v1/sites/default/pages", + { + title : "products", + slug : "products", + content: "Products are here", + order : 10 + } + ); + expect( event.getResponse() ).toHaveStatus( 400, + event.getResponse().getMessagesString() ); + expect( event.getResponse() ).toHaveInvalidData( "slug", "is not unique" ); + } + ); + } + ); + given( + "no content on a new content object", + () => { + then( + "it should display an error message", + () => { + var event = this.post( "cbapi/v1/sites/default/pages", + { slug: "A nice site" } ); + expect( event.getResponse() ).toHaveStatus( 400, + event.getResponse().getMessagesString() ); + // debug( event.getResponse().getMemento() ); - expect( event.getResponse().getMessages() ).toInclude( "content is required" ); - } ); - } ); - given( "invalid data but good content", function(){ - then( "it should display an error message", function(){ - var event = this.post( - "cbapi/v1/sites/default/pages", - { content : "Hello from bdd test land!" } + expect( event.getResponse().getMessages() ).toInclude( "content is required" ); + } + ); + } ); - expect( event.getResponse() ).toHaveStatus( 400, event.getResponse().getMessagesString() ); - expect( event.getResponse() ).toHaveInvalidData( "slug", "is required" ); - expect( event.getResponse() ).toHaveInvalidData( "title", "is required" ); - } ); - } ); - } ); // end create story + given( + "invalid data but good content", + () => { + then( + "it should display an error message", + () => { + var event = this.post( + "cbapi/v1/sites/default/pages", + { content: "Hello from bdd test land!" } + ); + expect( event.getResponse() ).toHaveStatus( 400, + event.getResponse().getMessagesString() ); + expect( event.getResponse() ).toHaveInvalidData( "slug", "is required" ); + expect( event.getResponse() ).toHaveInvalidData( "title", "is required" ); + } + ); + } + ); + } + ); // end create story - story( "I want to edit a page", function(){ - given( "a valid id/slug and valid data", function(){ - then( "then it should update a content item", function(){ - getCache( "template" ).clearAll(); - withRollback( function(){ - var event = this.put( - "/cbapi/v1/sites/default/pages/products", - { - content : "I am a new piece of content for the products!", - changelog : "Update from a bdd test!" - } - ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData().renderedContent ).toInclude( - "I am a new piece of content for the products!" - ); - expect( event.getResponse().getData().activeContent.changelog ).toInclude( "bdd test" ); - } ); - } ); - } ); - given( "duplicate content slug", function(){ - then( "it should display an error message", function(){ - var event = this.put( - "cbapi/v1/sites/default/pages/products", - { - title : "products", - slug : "support", - content : "Products are here" + story( + "I want to edit a page", + () => { + given( + "a valid id/slug and valid data", + () => { + then( + "then it should update a content item", + () => { + getCache( "template" ).clearAll(); + withRollback( + () => { + var event = this.put( + "/cbapi/v1/sites/default/pages/products", + { + content : "I am a new piece of content for the products!", + changelog: "Update from a bdd test!" + } + ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData().renderedContent ).toInclude( "I am a new piece of content for the products!" ); + expect( event.getResponse().getData().activeContent.changelog ).toInclude( "bdd test" ); + } + ); + } + ); + } + ); + given( + "duplicate content slug", + () => { + then( + "it should display an error message", + () => { + var event = this.put( + "cbapi/v1/sites/default/pages/products", + { + title : "products", + slug : "support", + content: "Products are here" + } + ); + expect( event.getResponse() ).toHaveStatus( 400, + event.getResponse().getMessagesString() ); + expect( event.getResponse() ).toHaveInvalidData( "slug", "is not unique" ); + } + ); } ); - expect( event.getResponse() ).toHaveStatus( 400, event.getResponse().getMessagesString() ); - expect( event.getResponse() ).toHaveInvalidData( "slug", "is not unique" ); - } ); - } ); - given( "an invalid id or slug", function(){ - then( "then I should see an error message", function(){ - var event = this.put( "/cbapi/v1/sites/default/pages/bogusbaby", { content : "bogus" } ); - expect( event.getResponse() ).toHaveStatus( 404, event.getResponse().getMessagesString() ); - } ); - } ); - } ); // end edit story + given( + "an invalid id or slug", + () => { + then( + "then I should see an error message", + () => { + var event = this.put( + "/cbapi/v1/sites/default/pages/bogusbaby", + { content: "bogus" } + ); + expect( event.getResponse() ).toHaveStatus( 404, + event.getResponse().getMessagesString() ); + } + ); + } + ); + } + ); // end edit story - story( "I want to delete a page", function(){ - given( "a valid id/slug", function(){ - then( "then I should see the confirmation", function(){ - var testContent = variables.pageService.save( - variables.pageService.new( { - title : "bddtest", - slug : "bddtest", - content : "This is my awesome bdd test page", - publishedDate : dateTimeFormat( now(), "yyyy-mm-dd'T'HH:mm:ssZ", "UTC" ), - changelog : "My first creation from the bdd test", - site : variables.siteService.getDefaultSite(), - creator : variables.loggedInData.user - } ) + story( + "I want to delete a page", + () => { + given( + "a valid id/slug", + () => { + then( + "then I should see the confirmation", + () => { + var testContent = variables.pageService.save( + variables.pageService.new( + { + title : "bddtest", + slug : "bddtest", + content : "This is my awesome bdd test page", + publishedDate: dateTimeFormat( + now(), + "yyyy-mm-dd'T'HH:mm:ssZ", + "UTC" + ), + changelog: "My first creation from the bdd test", + site : variables.siteService.getDefaultSite(), + creator : variables.loggedInData.user + } + ) + ); + var event = this.delete( + "/cbapi/v1/sites/default/pages/#testContent.getContentID()#" + ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getMessagesString() ).toInclude( "deleted" ); + } + ); + } + ); + given( + "an invalid id or slug", + () => { + then( + "then I should see an error message", + () => { + var event = this.delete( "/cbapi/v1/sites/default/pages/bogusbogus" ); + expect( event.getResponse() ).toHaveStatus( 404, + event.getResponse().getMessagesString() ); + } + ); + } ); - var event = this.delete( "/cbapi/v1/sites/default/pages/#testContent.getContentID()#" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getMessagesString() ).toInclude( "deleted" ); - } ); - } ); - given( "an invalid id or slug", function(){ - then( "then I should see an error message", function(){ - var event = this.delete( "/cbapi/v1/sites/default/pages/bogusbogus" ); - expect( event.getResponse() ).toHaveStatus( 404, event.getResponse().getMessagesString() ); - } ); - } ); - } ); // end delete story - } ); // end describe + } + ); // end delete story + } + ); // end describe } - // end run -} + + // end run +} \ No newline at end of file diff --git a/tests/specs/contentbox-api/RelocationsSpec.cfc b/tests/specs/contentbox-api/RelocationsSpec.cfc index db110b18a3..82c4868188 100644 --- a/tests/specs/contentbox-api/RelocationsSpec.cfc +++ b/tests/specs/contentbox-api/RelocationsSpec.cfc @@ -1,6 +1,6 @@ component extends="tests.resources.BaseApiTest" { - property name="siteService" inject="siteService@contentbox"; + property name="RelocationService" inject="RelocationService@contentbox"; /*********************************** LIFE CYCLE Methods ***********************************/ @@ -8,25 +8,25 @@ component extends="tests.resources.BaseApiTest" { /** * executes before all suites+specs in the run() method */ - function beforeAll(){ + function beforeAll() { super.beforeAll(); // Log in admin - variables.loggedInData = loginUser(); - variables.testSite = getDefaultSite(); + variables.loggedInData = loginUser(); + variables.testSite = getDefaultSite(); variables.testRelocation = variables.relocationService.new( - properties = { - "slug" : createUUID(), - "target" : createUUID(), - "site" : testSite - } - ); + properties = { + "slug" : createUUID(), + "target": createUUID(), + "site" : testSite + } + ); variables.RelocationService.save( testRelocation ); } /** * executes after all suites+specs in the run() method */ - function afterAll(){ + function afterAll() { if ( variables.keyExists( "testRelocation" ) ) { variables.relocationService.deleteWhere( slug = testRelocation.getSlug() ); } @@ -35,112 +35,202 @@ component extends="tests.resources.BaseApiTest" { /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ + function run( testResults, testBox ) { // all your suites go here. - describe( "Relocations API Suite", function(){ - beforeEach( function( currentSpec ){ - // Setup as a new ColdBox request for this suite, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST. - setup(); - } ); + describe( + "Relocations API Suite", + () => { + beforeEach( + ( currentSpec ) => { + // Setup as a new ColdBox request for this suite, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST. + setup(); + } + ); - story( "I want to view a Relocation by id or slug", function(){ - given( "a valid id", function(){ - then( "then I should get the requested Relocation", function(){ - var event = this.get( "/cbapi/v1/sites/default/relocations/#testRelocation.getRelocationID()#" ); - expect( event.getResponse() ).toHaveStatus( 200 ); - expect( event.getResponse().getData().slug ).toBe( testRelocation.getSlug() ); - } ); - } ); - given( "an invalid id or slug", function(){ - then( "then I should see an error message", function(){ - var event = this.get( "/cbapi/v1/sites/default/relocations/XYZ" ); - expect( event.getResponse() ).toHaveStatus( 404 ); - } ); - } ); - } ); // end story view site by id or slug + story( + "I want to view a Relocation by id or slug", + () => { + given( + "a valid id", + () => { + then( + "then I should get the requested Relocation", + () => { + var event = this.get( + "/cbapi/v1/sites/default/relocations/#testRelocation.getRelocationID()#" + ); + expect( event.getResponse() ).toHaveStatus( 200 ); + expect( event.getResponse().getData().slug ).toBe( testRelocation.getSlug() ); + } + ); + } + ); + given( + "an invalid id or slug", + () => { + then( + "then I should see an error message", + () => { + var event = this.get( "/cbapi/v1/sites/default/relocations/XYZ" ); + expect( event.getResponse() ).toHaveStatus( 404 ); + } + ); + } + ); + } + ); // end story view site by id or slug - story( "I want to list all site relocations", function(){ - given( "no options", function(){ - then( "it can display all site relocations", function(){ - var event = this.get( "/cbapi/v1/sites/default/relocations" ); - expect( event.getResponse() ).toHaveStatus( 200 ); - expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); - } ); - } ); - } ); // end story list all sites + story( + "I want to list all site relocations", + () => { + given( + "no options", + () => { + then( + "it can display all site relocations", + () => { + var event = this.get( "/cbapi/v1/sites/default/relocations" ); + expect( event.getResponse() ).toHaveStatus( 200 ); + expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); + } + ); + } + ); + } + ); // end story list all sites - story( "I want to create a site Relocation", function(){ - given( "valid incoming data", function(){ - then( "then I should see the confirmation", function(){ - withRollback( function(){ - var event = this.post( - "cbapi/v1/sites/default/relocations", - { target : "bddtest", slug : "bddtest" } - ); - expect( event.getResponse() ).toHaveStatus( 200 ); - expect( event.getResponse().getData().relocationID ).notToBeEmpty(); - expect( event.getResponse().getData().slug ).toBe( "bddtest" ); - } ); - } ); - } ); - given( "duplicate Relocation slug", function(){ - then( "it should display an error message", function(){ - var event = this.post( - "cbapi/v1/sites/default/relocations", - { "slug" : testRelocation.getSlug(), target : "coldbox" } + story( + "I want to create a site Relocation", + () => { + given( + "valid incoming data", + () => { + then( + "then I should see the confirmation", + () => { + withRollback( + () => { + var event = this.post( + "cbapi/v1/sites/default/relocations", + { target: "bddtest", slug: "bddtest" } + ); + expect( event.getResponse() ).toHaveStatus( 200 ); + expect( event.getResponse().getData().relocationID ).notToBeEmpty(); + expect( event.getResponse().getData().slug ).toBe( "bddtest" ); + } + ); + } + ); + } + ); + given( + "duplicate Relocation slug", + () => { + then( + "it should display an error message", + () => { + var event = this.post( + "cbapi/v1/sites/default/relocations", + { "slug": testRelocation.getSlug(), target: "coldbox" } + ); + expect( event.getResponse() ).toHaveStatus( 400 ); + expect( event.getResponse() ).toHaveInvalidData( "slug", "is not unique" ); + } + ); + } + ); + given( + "invalid data", + () => { + then( + "it should display an error message", + () => { + var event = this.post( + "cbapi/v1/sites/default/relocations", + { name: "A nice Relocation" } + ); + expect( event.getResponse() ).toHaveStatus( 400 ); + expect( event.getResponse() ).toHaveInvalidData( "slug", "is required" ); + } + ); + } ); - expect( event.getResponse() ).toHaveStatus( 400 ); - expect( event.getResponse() ).toHaveInvalidData( "slug", "is not unique" ); - } ); - } ); - given( "invalid data", function(){ - then( "it should display an error message", function(){ - var event = this.post( "cbapi/v1/sites/default/relocations", { name : "A nice Relocation" } ); - expect( event.getResponse() ).toHaveStatus( 400 ); - expect( event.getResponse() ).toHaveInvalidData( "slug", "is required" ); - } ); - } ); - } ); // end create story + } + ); // end create story - story( "I want to edit a Relocation", function(){ - given( "a valid id/slug and valid data", function(){ - then( "then it should update a Relocation", function(){ - withRollback( function(){ - var event = this.put( - "/cbapi/v1/sites/default/relocations/#testRelocation.getRelocationID()#", - { target : "foo" } - ); - expect( event.getResponse() ).toHaveStatus( 200 ); - expect( event.getResponse().getData().target ).toBe( "foo" ); - } ); - } ); - } ); - given( "an invalid id or slug", function(){ - then( "then I should see an error message", function(){ - var event = this.put( "/cbapi/v1/sites/default/relocations/123" ); - expect( event.getResponse() ).toHaveStatus( 404 ); - } ); - } ); - } ); // end edit story - story( "I want to delete a Relocation", function(){ - given( "a valid id/slug", function(){ - then( "then I should see the confirmation", function(){ - var event = this.delete( - "/cbapi/v1/sites/default/relocations/#variables.testRelocation.getRelocationID()#" + story( + "I want to edit a Relocation", + () => { + given( + "a valid id/slug and valid data", + () => { + then( + "then it should update a Relocation", + () => { + withRollback( + () => { + var event = this.put( + "/cbapi/v1/sites/default/relocations/#testRelocation.getRelocationID()#", + { target: "foo" } + ); + expect( event.getResponse() ).toHaveStatus( 200 ); + expect( event.getResponse().getData().target ).toBe( "foo" ); + } + ); + } + ); + } ); - expect( event.getResponse() ).toHaveStatus( 200 ); - expect( event.getResponse().getMessagesString() ).toInclude( "deleted" ); - } ); - } ); - given( "an invalid id or slug", function(){ - then( "then I should see an error message", function(){ - var event = this.delete( "/cbapi/v1/sites/default/relocations/1232222" ); - expect( event.getResponse() ).toHaveStatus( 404 ); - } ); - } ); - } ); // end delete story - } ); // end describe + given( + "an invalid id or slug", + () => { + then( + "then I should see an error message", + () => { + var event = this.put( "/cbapi/v1/sites/default/relocations/123" ); + expect( event.getResponse() ).toHaveStatus( 404 ); + } + ); + } + ); + } + ); // end edit story + story( + "I want to delete a Relocation", + () => { + given( + "a valid id/slug", + () => { + then( + "then I should see the confirmation", + () => { + var event = this.delete( + "/cbapi/v1/sites/default/relocations/#variables.testRelocation.getRelocationID()#" + ); + expect( event.getResponse() ).toHaveStatus( 200 ); + expect( event.getResponse().getMessagesString() ).toInclude( "deleted" ); + } + ); + } + ); + given( + "an invalid id or slug", + () => { + then( + "then I should see an error message", + () => { + var event = this.delete( "/cbapi/v1/sites/default/relocations/1232222" ); + expect( event.getResponse() ).toHaveStatus( 404 ); + } + ); + } + ); + } + ); // end delete story + } + ); // end describe } - // end run -} + + // end run +} \ No newline at end of file diff --git a/tests/specs/contentbox-api/SettingsSpec.cfc b/tests/specs/contentbox-api/SettingsSpec.cfc index f06ec1a257..702733e729 100644 --- a/tests/specs/contentbox-api/SettingsSpec.cfc +++ b/tests/specs/contentbox-api/SettingsSpec.cfc @@ -5,7 +5,7 @@ component extends="tests.resources.BaseApiTest" { /** * executes before all suites+specs in the run() method */ - function beforeAll(){ + function beforeAll() { super.beforeAll(); // Log in admin variables.loggedInData = loginUser(); @@ -14,34 +14,47 @@ component extends="tests.resources.BaseApiTest" { /** * executes after all suites+specs in the run() method */ - function afterAll(){ + function afterAll() { super.afterAll(); } /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ + function run( testResults, testBox ) { // all your suites go here. - describe( "Global Settings API Suite", function(){ - beforeEach( function( currentSpec ){ - // Setup as a new ColdBox request for this suite, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST. - setup(); - } ); - - story( "I want to get global settings", function(){ - given( "a valid request", function(){ - then( "it can display all global settings", function(){ - var event = this.get( "/cbapi/v1/settings" ); - expect( event.getResponse() ).toHaveStatus( 200 ); - expect( event.getResponse().getData() ).toBeStruct().notToBeEmpty(); - expect( event.getResponse().getData() ).notToHaveKey( - "cb_enc_key,cb_salt,cb_site_mail_password" + describe( + "Global Settings API Suite", + () => { + beforeEach( + ( currentSpec ) => { + // Setup as a new ColdBox request for this suite, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST. + setup(); + } + ); + + story( + "I want to get global settings", + () => { + given( + "a valid request", + () => { + then( + "it can display all global settings", + () => { + var event = this.get( "/cbapi/v1/settings" ); + expect( event.getResponse() ).toHaveStatus( 200 ); + expect( event.getResponse().getData() ).toBeStruct().notToBeEmpty(); + expect( event.getResponse().getData() ).notToHaveKey( "cb_enc_key,cb_salt,cb_site_mail_password" ); + } + ); + } ); - } ); - } ); - } ); // end story list all sites - } ); // end describe + } + ); // end story list all sites + } + ); // end describe } - // end run -} + + // end run +} \ No newline at end of file diff --git a/tests/specs/contentbox-api/SiteSettingsSpec.cfc b/tests/specs/contentbox-api/SiteSettingsSpec.cfc index 248a6f6ebc..fda7a84bbb 100644 --- a/tests/specs/contentbox-api/SiteSettingsSpec.cfc +++ b/tests/specs/contentbox-api/SiteSettingsSpec.cfc @@ -5,7 +5,7 @@ component extends="tests.resources.BaseApiTest" { /** * executes before all suites+specs in the run() method */ - function beforeAll(){ + function beforeAll() { super.beforeAll(); // Log in admin variables.loggedInData = loginUser(); @@ -14,38 +14,59 @@ component extends="tests.resources.BaseApiTest" { /** * executes after all suites+specs in the run() method */ - function afterAll(){ + function afterAll() { super.afterAll(); } /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ + function run( testResults, testBox ) { // all your suites go here. - describe( "Sites Settings API Suite", function(){ - beforeEach( function( currentSpec ){ - // Setup as a new ColdBox request for this suite, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST. - setup(); - } ); - - story( "I want to get site settings", function(){ - given( "a valid site slug", function(){ - then( "it can display all site settings", function(){ - var event = this.get( "/cbapi/v1/sites/default/settings" ); - expect( event.getResponse() ).toHaveStatus( 200 ); - expect( event.getResponse().getData() ).toBeStruct().notToBeEmpty(); - } ); - } ); - - given( "an invalid site slug", function(){ - then( "it will show me an error", function(){ - var event = this.get( "/cbapi/v1/sites/bogus/settings" ); - expect( event.getResponse() ).toHaveStatus( 404 ); - } ); - } ); - } ); // end story list all sites - } ); // end describe + describe( + "Sites Settings API Suite", + () => { + beforeEach( + ( currentSpec ) => { + // Setup as a new ColdBox request for this suite, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST. + setup(); + } + ); + + story( + "I want to get site settings", + () => { + given( + "a valid site slug", + () => { + then( + "it can display all site settings", + () => { + var event = this.get( "/cbapi/v1/sites/default/settings" ); + expect( event.getResponse() ).toHaveStatus( 200 ); + expect( event.getResponse().getData() ).toBeStruct().notToBeEmpty(); + } + ); + } + ); + + given( + "an invalid site slug", + () => { + then( + "it will show me an error", + () => { + var event = this.get( "/cbapi/v1/sites/bogus/settings" ); + expect( event.getResponse() ).toHaveStatus( 404 ); + } + ); + } + ); + } + ); // end story list all sites + } + ); // end describe } - // end run -} + + // end run +} \ No newline at end of file diff --git a/tests/specs/contentbox-api/SitesSpec.cfc b/tests/specs/contentbox-api/SitesSpec.cfc index a92c8feab2..d3e6388bbe 100644 --- a/tests/specs/contentbox-api/SitesSpec.cfc +++ b/tests/specs/contentbox-api/SitesSpec.cfc @@ -1,5 +1,4 @@ component extends="tests.resources.BaseApiTest" { - property name="siteService" inject="siteService@contentbox"; /*********************************** LIFE CYCLE Methods ***********************************/ @@ -7,7 +6,7 @@ component extends="tests.resources.BaseApiTest" { /** * executes before all suites+specs in the run() method */ - function beforeAll(){ + function beforeAll() { super.beforeAll(); // Log in admin variables.loggedInData = loginUser(); @@ -16,191 +15,309 @@ component extends="tests.resources.BaseApiTest" { /** * executes after all suites+specs in the run() method */ - function afterAll(){ + function afterAll() { super.afterAll(); } /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ + function run( testResults, testBox ) { // all your suites go here. - describe( "Sites API Suite", function(){ - beforeEach( function( currentSpec ){ - // Setup as a new ColdBox request for this suite, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST. - setup(); - } ); - - story( "I want to view a site by id or slug", function(){ - given( "an valid id", function(){ - then( "then I should get the requested site", function(){ - var testSite = getDefaultSite(); - var event = this.get( "/cbapi/v1/sites/#testSite.getSiteID()#" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData().slug ).toBe( "default" ); - } ); - } ); - given( "an valid slug", function(){ - then( "then I should get the requested site", function(){ - var event = this.get( "/cbapi/v1/sites/default" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData().slug ).toBe( "default" ); - } ); - } ); - given( "an invalid id or slug", function(){ - then( "then I should see an error message", function(){ - var event = this.get( "/cbapi/v1/sites/123" ); - expect( event.getResponse() ).toHaveStatus( 404, event.getResponse().getMessagesString() ); - } ); - } ); - } ); // end story view site by id or slug + describe( + "Sites API Suite", + () => { + beforeEach( + ( currentSpec ) => { + // Setup as a new ColdBox request for this suite, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST. + setup(); + } + ); - story( "I want to list all sites", function(){ - given( "no options", function(){ - then( "it can display all sites", function(){ - var event = this.get( "/cbapi/v1/sites" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); - event - .getResponse() - .getData() - .each( function( thisItem ){ - expect( thisItem.isActive ).toBeTrue( thisItem.toString() ); - } ); - } ); - } ); - given( "inactive flag option", function(){ - then( "it can display inactive sites", function(){ - var event = this.get( "/cbapi/v1/sites?isActive=false" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - event - .getResponse() - .getData() - .each( function( thisItem ){ - expect( thisItem.isActive ).toBeFalse(); - } ); - } ); - } ); - given( "a name or description search", function(){ - then( "it can find the site", function(){ - var event = this.get( "/cbapi/v1/sites?search=default" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - event - .getResponse() - .getData() - .each( function( thisItem ){ - expect( thisItem.slug ).toBe( "default" ); - } ); - } ); - } ); - } ); // end story list all sites + story( + "I want to view a site by id or slug", + () => { + given( + "an valid id", + () => { + then( + "then I should get the requested site", + () => { + var testSite = getDefaultSite(); + var event = this.get( "/cbapi/v1/sites/#testSite.getSiteID()#" ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData().slug ).toBe( "default" ); + } + ); + } + ); + given( + "an valid slug", + () => { + then( + "then I should get the requested site", + () => { + var event = this.get( "/cbapi/v1/sites/default" ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData().slug ).toBe( "default" ); + } + ); + } + ); + given( + "an invalid id or slug", + () => { + then( + "then I should see an error message", + () => { + var event = this.get( "/cbapi/v1/sites/123" ); + expect( event.getResponse() ).toHaveStatus( 404, + event.getResponse().getMessagesString() ); + } + ); + } + ); + } + ); // end story view site by id or slug - story( "I want to create a site", function(){ - given( "a valid id/slug", function(){ - then( "then I should see the confirmation", function(){ - withRollback( function(){ - var event = this.post( - "cbapi/v1/sites", - { - name : "bddtest", - slug : "bddtest", - description : "my bdd test site", - domain : "bddtest.com", - domainRegex : "bddtest\.com", - domainAliases : "[]", - activeTheme : "default", - homepage : "cbBlog" - } - ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData().siteID ).notToBeEmpty(); - expect( event.getResponse().getData().slug ).toBe( "bddtest" ); - } ); - } ); - } ); - given( "duplicate site slug", function(){ - then( "it should display an error message", function(){ - var event = this.post( - "cbapi/v1/sites", - { - name : "default", - slug : "default", - description : "my bdd test site", - domain : "bddtest.com", - domainRegex : "bddtest\.com", - domainAliases : "[]", - activeTheme : "default", - homepage : "cbBlog" + story( + "I want to list all sites", + () => { + given( + "no options", + () => { + then( + "it can display all sites", + () => { + var event = this.get( "/cbapi/v1/sites" ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData() ).toBeArray().notToBeEmpty(); + event + .getResponse() + .getData() + .each( + ( thisItem ) => { + expect( thisItem.isActive ).toBeTrue( thisItem.toString() ); + } + ); + } + ); } ); - expect( event.getResponse() ).toHaveStatus( 400, event.getResponse().getMessagesString() ); - expect( event.getResponse() ).toHaveInvalidData( "slug", "is not unique" ); - } ); - } ); - given( "invalid data", function(){ - then( "it should display an error message", function(){ - var event = this.post( "cbapi/v1/sites", { description : "A nice site" } ); - expect( event.getResponse() ).toHaveStatus( 400, event.getResponse().getMessagesString() ); - expect( event.getResponse() ).toHaveInvalidData( "name", "is required" ); - expect( event.getResponse() ).toHaveInvalidData( "slug", "is required" ); - expect( event.getResponse() ).toHaveInvalidData( "domain", "is required" ); - } ); - } ); - } ); // end create story + given( + "inactive flag option", + () => { + then( + "it can display inactive sites", + () => { + var event = this.get( "/cbapi/v1/sites?isActive=false" ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + event + .getResponse() + .getData() + .each( + ( thisItem ) => { + expect( thisItem.isActive ).toBeFalse(); + } + ); + } + ); + } + ); + given( + "a name or description search", + () => { + then( + "it can find the site", + () => { + var event = this.get( "/cbapi/v1/sites?search=default" ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + event + .getResponse() + .getData() + .each( + ( thisItem ) => { + expect( thisItem.slug ).toBe( "default" ); + } + ); + } + ); + } + ); + } + ); // end story list all sites - story( "I want to edit a site", function(){ - given( "a valid id/slug and valid data", function(){ - then( "then it should update a site", function(){ - withRollback( function(){ - var event = this.put( - "/cbapi/v1/sites/default", - { description : "bdd test baby!", isActive : false } - ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getData().description ).toInclude( "bdd test baby!" ); - expect( event.getResponse().getData().isActive ).toBeFalse(); - } ); - } ); - } ); - given( "an invalid id or slug", function(){ - then( "then I should see an error message", function(){ - var event = this.put( "/cbapi/v1/sites/123" ); - expect( event.getResponse() ).toHaveStatus( 404, event.getResponse().getMessagesString() ); - } ); - } ); - } ); // end edit story + story( + "I want to create a site", + () => { + given( + "a valid id/slug", + () => { + then( + "then I should see the confirmation", + () => { + withRollback( + () => { + var event = this.post( + "cbapi/v1/sites", + { + name : "bddtest", + slug : "bddtest", + description : "my bdd test site", + domain : "bddtest.com", + domainRegex : "bddtest\.com", + domainAliases: "[]", + activeTheme : "default", + homepage : "cbBlog" + } + ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData().siteID ).notToBeEmpty(); + expect( event.getResponse().getData().slug ).toBe( "bddtest" ); + } + ); + } + ); + } + ); + given( + "duplicate site slug", + () => { + then( + "it should display an error message", + () => { + var event = this.post( + "cbapi/v1/sites", + { + name : "default", + slug : "default", + description : "my bdd test site", + domain : "bddtest.com", + domainRegex : "bddtest\.com", + domainAliases: "[]", + activeTheme : "default", + homepage : "cbBlog" + } + ); + expect( event.getResponse() ).toHaveStatus( 400, + event.getResponse().getMessagesString() ); + expect( event.getResponse() ).toHaveInvalidData( "slug", "is not unique" ); + } + ); + } + ); + given( + "invalid data", + () => { + then( + "it should display an error message", + () => { + var event = this.post( "cbapi/v1/sites", { description: "A nice site" } ); + expect( event.getResponse() ).toHaveStatus( 400, + event.getResponse().getMessagesString() ); + expect( event.getResponse() ).toHaveInvalidData( "name", "is required" ); + expect( event.getResponse() ).toHaveInvalidData( "slug", "is required" ); + expect( event.getResponse() ).toHaveInvalidData( "domain", "is required" ); + } + ); + } + ); + } + ); // end create story - story( "I want to delete a site", function(){ - given( "a valid id/slug", function(){ - then( "then I should see the confirmation", function(){ - var siteId = createUUID(); - var testSite = variables.siteService.save( - variables.siteService.new( { - name : "bddtest-#siteId#", - slug : "bddtest-#siteId#", - description : "my bdd test site", - domain : "bddtest.com", - domainRegex : "bddtest\.com", - domainAliases : "[]", - activeTheme : "default", - homepage : "cbBlog" - } ) + story( + "I want to edit a site", + () => { + given( + "a valid id/slug and valid data", + () => { + then( + "then it should update a site", + () => { + withRollback( + () => { + var event = this.put( + "/cbapi/v1/sites/default", + { description: "bdd test baby!", isActive: false } + ); + expect( event.getResponse() ).toHaveStatus( 200, + event.getResponse().getMessagesString() ); + expect( event.getResponse().getData().description ).toInclude( "bdd test baby!" ); + expect( event.getResponse().getData().isActive ).toBeFalse(); + } + ); + } + ); + } ); - // clear the session to make sure our delete is working with a new entity - ormClearSession(); - var event = this.delete( "/cbapi/v1/sites/#testSite.getSiteId()#" ); - expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); - expect( event.getResponse().getMessagesString() ).toInclude( "deleted" ); - } ); - } ); - given( "an invalid id or slug", function(){ - then( "then I should see an error message", function(){ - var event = this.delete( "/cbapi/v1/sites/123" ); - expect( event.getResponse() ).toHaveStatus( 404, event.getResponse().getMessagesString() ); + given( + "an invalid id or slug", + () => { + then( + "then I should see an error message", + () => { + var event = this.put( "/cbapi/v1/sites/123" ); + expect( event.getResponse() ).toHaveStatus( 404, + event.getResponse().getMessagesString() ); + } + ); + } + ); + } + ); // end edit story + + story( "I want to delete a site", () => { + given( "a valid id/slug", () => { + then( + "then I should see the confirmation", + () => { + var siteId = createUUID(); + var testSite = variables.siteService.save( + variables.siteService.new( + { + name : "bddtest-#siteId#", + slug : "bddtest-#siteId#", + description : "my bdd test site", + domain : "bddtest.com", + domainRegex : "bddtest\.com", + domainAliases: "[]", + activeTheme : "default", + homepage : "cbBlog" + } + ) + ); + // clear the session to make sure our delete is working with a new entity + ormClearSession(); + var event = this.delete( "/cbapi/v1/sites/#testSite.getSiteId()#" ); + expect( event.getResponse() ).toHaveStatus( 200, event.getResponse().getMessagesString() ); + expect( event.getResponse().getMessagesString() ).toInclude( "deleted" ); + } + ); } ); + given( + "an invalid id or slug", + () => { + then( + "then I should see an error message", + () => { + var event = this.delete( "/cbapi/v1/sites/123" ); + expect( event.getResponse() ).toHaveStatus( 404, + event.getResponse().getMessagesString() ); + } + ); + } + ); } ); - } ); // end delete story - } ); // end describe + // end delete story + } + ); // end describe } - // end run -} + + // end run +} \ No newline at end of file diff --git a/tests/specs/contentbox-api/authSpec.cfc b/tests/specs/contentbox-api/authSpec.cfc index 45ffeac013..4bf50ca50d 100644 --- a/tests/specs/contentbox-api/authSpec.cfc +++ b/tests/specs/contentbox-api/authSpec.cfc @@ -1,201 +1,327 @@ component extends="tests.resources.BaseApiTest" { /*********************************** LIFE CYCLE Methods ***********************************/ - function beforeAll(){ + function beforeAll() { super.beforeAll(); } - function afterAll(){ + function afterAll() { // do your own stuff here super.afterAll(); } /*********************************** BDD SUITES ***********************************/ - function run(){ - describe( "Authentication Specs", function(){ - beforeEach( function( currentSpec ){ - // Setup as a new ColdBox request for this suite, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST. - setup(); - // Make sure nothing is logged in to start our calls - securityService.logout(); - jwt.getTokenStorage().clearAll(); - } ); + function run() { + describe( + "Authentication Specs", + () => { + beforeEach( + ( currentSpec ) => { + // Setup as a new ColdBox request for this suite, VERY IMPORTANT. ELSE EVERYTHING LOOKS LIKE THE SAME REQUEST. + setup(); + // Make sure nothing is logged in to start our calls + securityService.logout(); + jwt.getTokenStorage().clearAll(); + } + ); - story( "I want to authenticate a user via username/password and receive a JWT token", function(){ - given( "a valid username and password", function(){ - then( "I will be authenticated and will receive the JWT token", function(){ - // Use a user in the seeded db - var event = this.post( - "/cbapi/v1/login", - { - username : variables.testAdminUsername, - password : variables.testAdminPassword + story( + "I want to authenticate a user via username/password and receive a JWT token", + () => { + given( + "a valid username and password", + () => { + then( + "I will be authenticated and will receive the JWT token", + () => { + // Use a user in the seeded db + var event = this.post( + "/cbapi/v1/login", + { + username: variables.testAdminUsername, + password: variables.testAdminPassword + } + ); + var response = event.getPrivateValue( "Response" ); + expect( response.getError() ).toBeFalse( response.getMessagesString() ); + expect( response.getData() ).toHaveKey( "tokens,author" ); + // debug( response.getData() ); + var decoded = jwt.decode( response.getData().tokens.access_token ); + expect( decoded.sub ).toBe( response.getData().author.authorID ); + expect( decoded.exp ).toBeGTE( + dateAdd( + "h", + 1, + decoded.iat + ) + ); + var decoded = jwt.decode( response.getData().tokens.refresh_token ); + expect( decoded.sub ).toBe( response.getData().author.authorID ); + expect( response.getData().author.email ).toBe( variables.testAdminEmail ); + } + ); } ); - var response = event.getPrivateValue( "Response" ); - expect( response.getError() ).toBeFalse( response.getMessagesString() ); - expect( response.getData() ).toHaveKey( "tokens,author" ); - // debug( response.getData() ); - var decoded = jwt.decode( response.getData().tokens.access_token ); - expect( decoded.sub ).toBe( response.getData().author.authorID ); - expect( decoded.exp ).toBeGTE( dateAdd( "h", 1, decoded.iat ) ); - var decoded = jwt.decode( response.getData().tokens.refresh_token ); - expect( decoded.sub ).toBe( response.getData().author.authorID ); - expect( response.getData().author.email ).toBe( variables.testAdminEmail ); - } ); - } ); - given( "invalid username and password", function(){ - then( "I will receive a 401 invalid credentials exception ", function(){ - var event = this.post( "/cbapi/v1/login", { username : "invalid", password : "invalid" } ); - var response = event.getPrivateValue( "Response" ); - expect( response.getError() ).toBeTrue(); - expect( response.getStatusCode() ).toBe( 401 ); - } ); - } ); - } ); + given( + "invalid username and password", + () => { + then( + "I will receive a 401 invalid credentials exception ", + () => { + var event = this.post( + "/cbapi/v1/login", + { username: "invalid", password: "invalid" } + ); + var response = event.getPrivateValue( "Response" ); + expect( response.getError() ).toBeTrue(); + expect( response.getStatusCode() ).toBe( 401 ); + } + ); + } + ); + } + ); - story( "I want to be able to logout from the system using my JWT token", function(){ - given( "a valid incoming jwt token and I issue a logout", function(){ - then( "my token should become invalidated and I will be logged out", function(){ - // Log in - var token = jwt.attempt( variables.testAdminUsername, variables.testAdminPassword ); - var payload = jwt.decode( token.access_token ); + story( + "I want to be able to logout from the system using my JWT token", + () => { + given( + "a valid incoming jwt token and I issue a logout", + () => { + then( + "my token should become invalidated and I will be logged out", + () => { + // Log in + var token = jwt.attempt( variables.testAdminUsername, + variables.testAdminPassword ); + var payload = jwt.decode( token.access_token ); - // Now Logout - var event = post( "/cbapi/v1/logout", { "x-auth-token" : token.access_token } ); - var response = event.getPrivateValue( "Response" ); - expect( response.getError() ).toBeFalse( response.getMessagesString() ); - expect( response.getStatusCode() ).toBe( 200 ); - expect( securityService.isLoggedIn() ).toBeFalse(); - } ); - } ); - given( "an invalid incoming jwt token and I issue a logout", function(){ - then( "I should see an error message", function(){ - // Now Logout - var event = post( "/cbapi/v1/logout", { "x-auth-token" : "123" } ); - var response = event.getPrivateValue( "Response" ); - expect( response.getError() ).toBeTrue( response.getMessagesString() ); - expect( response.getStatusCode() ).toBe( 401 ); - } ); - } ); - } ); + // Now Logout + var event = post( + "/cbapi/v1/logout", + { "x-auth-token": token.access_token } + ); + var response = event.getPrivateValue( "Response" ); + expect( response.getError() ).toBeFalse( response.getMessagesString() ); + expect( response.getStatusCode() ).toBe( 200 ); + expect( securityService.isLoggedIn() ).toBeFalse(); + } + ); + } + ); + given( + "an invalid incoming jwt token and I issue a logout", + () => { + then( + "I should see an error message", + () => { + // Now Logout + var event = post( "/cbapi/v1/logout", { "x-auth-token": "123" } ); + var response = event.getPrivateValue( "Response" ); + expect( response.getError() ).toBeTrue( response.getMessagesString() ); + expect( response.getStatusCode() ).toBe( 401 ); + } + ); + } + ); + } + ); - story( "I want to be able to know who I am by passing my token", function(){ - given( "an valid token", function(){ - then( "I should get my information", function(){ - var tokens = jwt.attempt( variables.testAdminUsername, variables.testAdminPassword ); - var payload = jwt.decode( tokens.access_token ); - var event = GET( "/cbapi/v1/whoami", { "x-auth-token" : tokens.access_token } ); - expect( event.getResponse() ).toHaveStatus( - 200, - event - .getResponse() - .getMemento() - .toString() + story( + "I want to be able to know who I am by passing my token", + () => { + given( + "an valid token", + () => { + then( + "I should get my information", + () => { + var tokens = jwt.attempt( variables.testAdminUsername, + variables.testAdminPassword ); + var payload = jwt.decode( tokens.access_token ); + var event = GET( + "/cbapi/v1/whoami", + { "x-auth-token": tokens.access_token } + ); + expect( event.getResponse() ).toHaveStatus( 200, + event + .getResponse() + .getMemento() + .toString() ); + expect( event.getResponse().getData().authorID ).toBe( payload.sub ); + } + ); + } ); - expect( event.getResponse().getData().authorID ).toBe( payload.sub ); - } ); - } ); - given( "an invalid token", function(){ - then( "I should get an error", function(){ - // Now Logout - var event = GET( "/cbapi/v1/whoami", { "x-auth-token" : "123" } ); - expect( event.getResponse() ).toHaveStatus( - 401, - event - .getResponse() - .getMemento() - .toString() + given( + "an invalid token", + () => { + then( + "I should get an error", + () => { + // Now Logout + var event = GET( "/cbapi/v1/whoami", { "x-auth-token": "123" } ); + expect( event.getResponse() ).toHaveStatus( 401, + event + .getResponse() + .getMemento() + .toString() ); + } + ); + } ); - } ); - } ); - } ); + } + ); - xstory( "I want to send a password reset reminder when I forget my password", function(){ - given( "an valid email", function(){ - then( "I should get a reminder sent", function(){ - // Now Logout - var event = POST( "/cbapi/v1/forgotPassword", { "email" : variables.testAdminUsername } ); - expect( event.getResponse() ).toHaveStatus( 200 ); - } ); - } ); - given( "an invalid email", function(){ - then( "I should get an error", function(){ - // Now Logout - var event = POST( "/cbapi/v1/forgotPassword", { "email" : "bogus@bogus.com" } ); - expect( event.getResponse() ).toHaveStatus( 404 ); - } ); - } ); - } ); + xstory( + "I want to send a password reset reminder when I forget my password", + () => { + given( + "an valid email", + () => { + then( + "I should get a reminder sent", + () => { + // Now Logout + var event = POST( + "/cbapi/v1/forgotPassword", + { "email": variables.testAdminUsername } + ); + expect( event.getResponse() ).toHaveStatus( 200 ); + } + ); + } + ); + given( + "an invalid email", + () => { + then( + "I should get an error", + () => { + // Now Logout + var event = POST( + "/cbapi/v1/forgotPassword", + { "email": "bogus@bogus.com" } + ); + expect( event.getResponse() ).toHaveStatus( 404 ); + } + ); + } + ); + } + ); - xstory( "I want to verify password reset tokens", function(){ - given( "a valid reset token", function(){ - then( "I should get a true validation", function(){ - var testUser = getInstance( "UserService" ).retrieveUserByUsername( - variables.testAdminUsername + xstory( + "I want to verify password reset tokens", + () => { + given( + "a valid reset token", + () => { + then( + "I should get a true validation", + () => { + var testUser = getInstance( "UserService" ).retrieveUserByUsername( variables.testAdminUsername ); + var token = securityService.generatePasswordResetToken( testUser ); + // Now Logout + var event = POST( "/cbapi/v1/verifyPasswordReset", { "token": token } ); + expect( event.getResponse() ).toHaveStatus( 200 ); + expect( event.getResponse().getData() ).toBeTrue(); + } + ); + } + ); + given( + "an invalid token", + () => { + then( + "I should get an error", + () => { + // Now Logout + var event = POST( + "/cbapi/v1/verifyPasswordReset", + { "token": "12312312sadfasd4" } + ); + expect( event.getResponse() ).toHaveStatus( 406 ); + expect( event.getResponse().getData() ).toBeFalse(); + } + ); + } ); - var token = securityService.generatePasswordResetToken( testUser ); - // Now Logout - var event = POST( "/cbapi/v1/verifyPasswordReset", { "token" : token } ); - expect( event.getResponse() ).toHaveStatus( 200 ); - expect( event.getResponse().getData() ).toBeTrue(); - } ); - } ); - given( "an invalid token", function(){ - then( "I should get an error", function(){ - // Now Logout - var event = POST( "/cbapi/v1/verifyPasswordReset", { "token" : "12312312sadfasd4" } ); - expect( event.getResponse() ).toHaveStatus( 406 ); - expect( event.getResponse().getData() ).toBeFalse(); - } ); - } ); - } ); + } + ); - xstory( "I want to reset a user password", function(){ - beforeEach( function( currentSpec ){ - testResetUser = getInstance( "UserService" ).retrieveUserByUsername( variables.testContractorEmail ); - testResetToken = securityService.generatePasswordResetToken( testResetUser ); - } ); + xstory( + "I want to reset a user password", + () => { + beforeEach( + ( currentSpec ) => { + testResetUser = getInstance( "UserService" ).retrieveUserByUsername( variables.testContractorEmail ); + testResetToken = securityService.generatePasswordResetToken( testResetUser ); + } + ); - given( "a valid reset token and not the previous password", function(){ - then( "I should reset the password", function(){ - // Now Logout - var event = POST( - "/cbapi/v1/resetPassword", - { - "token" : testResetToken, - "password" : "testing123", - "passwordConfirmation" : "testing123" + given( + "a valid reset token and not the previous password", + () => { + then( + "I should reset the password", + () => { + // Now Logout + var event = POST( + "/cbapi/v1/resetPassword", + { + "token" : testResetToken, + "password" : "testing123", + "passwordConfirmation": "testing123" + } + ); + expect( event.getResponse() ).toHaveStatus( 200 ); + expect( event.getResponse().getMessagesString() ).toInclude( "Password reset completed" ); + } + ); + } + ); + given( + "a valid token but incoming passwords don't match", + () => { + then( + "I should get an error", + () => { + // Now Logout + var event = POST( + "/cbapi/v1/resetPassword", + { + "token" : testResetToken, + "password" : "12345678abc$dd", + "passwordConfirmation": "12344" + } + ); + expect( event.getResponse() ).toHaveStatus( 400 ); + expect( event.getResponse().getMessagesString() ).toInclude( "Passwords do not match" ); + } + ); } ); - expect( event.getResponse() ).toHaveStatus( 200 ); - expect( event.getResponse().getMessagesString() ).toInclude( "Password reset completed" ); - } ); - } ); - given( "a valid token but incoming passwords don't match", function(){ - then( "I should get an error", function(){ - // Now Logout - var event = POST( - "/cbapi/v1/resetPassword", - { - "token" : testResetToken, - "password" : "12345678abc$dd", - "passwordConfirmation" : "12344" + given( + "an invalid token", + () => { + then( + "I should get an error", + () => { + // Now Logout + var event = POST( + "/cbapi/v1/resetPassword", + { "token": "12312312sadfasd4" } + ); + expect( event.getResponse() ).toHaveStatus( 500 ); + } + ); } ); - expect( event.getResponse() ).toHaveStatus( 400 ); - expect( event.getResponse().getMessagesString() ).toInclude( "Passwords do not match" ); - } ); - } ); - given( "an invalid token", function(){ - then( "I should get an error", function(){ - // Now Logout - var event = POST( "/cbapi/v1/resetPassword", { "token" : "12312312sadfasd4" } ); - expect( event.getResponse() ).toHaveStatus( 500 ); - } ); - } ); - } ); - } ); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox-installer/integration/HomeTest.cfc b/tests/specs/contentbox-web/contentbox-installer/integration/HomeTest.cfc index 28364ca2fa..338b71ad6a 100755 --- a/tests/specs/contentbox-web/contentbox-installer/integration/HomeTest.cfc +++ b/tests/specs/contentbox-web/contentbox-installer/integration/HomeTest.cfc @@ -2,22 +2,30 @@ component extends="tests.resources.BaseTest" { /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ + function run( testResults, testBox ) { // all your suites go here. - describe( "ContentBox Installer", function(){ - beforeEach( function( currentSpec ){ - setup(); - } ); + describe( + "ContentBox Installer", + () => { + beforeEach( ( currentSpec ) => { + setup(); + } ); - it( "Can startup the installer", function(){ - var e = execute( "contentbox-installer:Home.index" ); - } ); + it( + "Can startup the installer", + () => { + var e = execute( "contentbox-installer:Home.index" ); + } + ); - it( "Can finalize the installer", function(){ - var e = execute( "contentbox-installer:Home.finished" ); - } ); - } ); + it( + "Can finalize the installer", + () => { + var e = execute( "contentbox-installer:Home.finished" ); + } + ); + } + ); } -} - +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox-installer/unit/InstallerServiceTest.cfc b/tests/specs/contentbox-web/contentbox-installer/unit/InstallerServiceTest.cfc index b182c21472..07911f979d 100755 --- a/tests/specs/contentbox-web/contentbox-installer/unit/InstallerServiceTest.cfc +++ b/tests/specs/contentbox-web/contentbox-installer/unit/InstallerServiceTest.cfc @@ -1,36 +1,42 @@ -component extends="tests.resources.BaseTest" { +component extends="tests.resources.BaseTest" { /*********************************** LIFE CYCLE Methods ***********************************/ // executes before all suites+specs in the run() method - function beforeAll(){ + function beforeAll() { super.beforeAll(); super.setup(); - installer = getInstance( "InstallerService@cbi" ); + installer = getInstance( "InstallerService@cbi" ); resourcesPath = expandPath( "/tests/resources" ) & "/"; } - /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ + function run( testResults, testBox ) { // all your suites go here. - describe( "Installer Service", function(){ - it( "can process ColdBox Reinit passwords", function(){ - var setup = getInstance( "Setup@cbi" ); - var original = fileRead( resourcesPath & "config/Coldbox.cfc" ); + describe( + "Installer Service", + () => { + it( + "can process ColdBox Reinit passwords", + () => { + var setup = getInstance( "Setup@cbi" ); + var original = fileRead( resourcesPath & "config/Coldbox.cfc" ); + + try { + installer.setAppPath( resourcesPath ); + installer.processColdBoxPasswords( setup ); + var updated = fileRead( resourcesPath & "config/Coldbox.cfc" ); + expect( updated ).notToInclude( "@fwPassword@" ); + } catch (any e) { - try { - installer.setAppPath( resourcesPath ); - installer.processColdBoxPasswords( setup ); - var updated = fileRead( resourcesPath & "config/Coldbox.cfc" ); - expect( updated ).notToInclude( "@fwPassword@" ); - } catch ( any e ) { - } finally { - fileWrite( resourcesPath & "config/Coldbox.cfc", original ); - } - } ); - } ); + } finally { + fileWrite( resourcesPath & "config/Coldbox.cfc", original ); + } + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/contentbox-email-twofactor/EmailTwoFactorProviderTest.cfc b/tests/specs/contentbox-web/contentbox/contentbox-email-twofactor/EmailTwoFactorProviderTest.cfc index 94e9d8bf75..1d04e4a1a1 100644 --- a/tests/specs/contentbox-web/contentbox/contentbox-email-twofactor/EmailTwoFactorProviderTest.cfc +++ b/tests/specs/contentbox-web/contentbox/contentbox-email-twofactor/EmailTwoFactorProviderTest.cfc @@ -5,34 +5,51 @@ component extends="tests.resources.BaseTest" { /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ + function run( testResults, testBox ) { // all your suites go here. - describe( "Email Two Factor Provider", function(){ - beforeEach( function( currentSpec ){ - mockUser = getInstance( "authorService@contentbox" ).findByUsername( "lmajano" ); - provider = getInstance( "EmailTwoFactorProvider@contentbox-email-twofactor" ); - } ); + describe( + "Email Two Factor Provider", + () => { + beforeEach( + ( currentSpec ) => { + mockUser = getInstance( "authorService@contentbox" ).findByUsername( "lmajano" ); + provider = getInstance( "EmailTwoFactorProvider@contentbox-email-twofactor" ); + } + ); - it( "can get names", function(){ - expect( provider.getName() ).toBe( "email" ); - expect( provider.getDisplayName() ).toBe( "Email" ); - } ); + it( + "can get names", + () => { + expect( provider.getName() ).toBe( "email" ); + expect( provider.getDisplayName() ).toBe( "Email" ); + } + ); - it( "can get trusted devices", function(){ - expect( provider.allowTrustedDevice() ).toBeTrue(); - } ); + it( + "can get trusted devices", + () => { + expect( provider.allowTrustedDevice() ).toBeTrue(); + } + ); - it( "can generate validation tokens", function(){ - var token = provider.generateValidationToken( mockUser ); - expect( token ).notToBeEmpty(); - } ); + it( + "can generate validation tokens", + () => { + var token = provider.generateValidationToken( mockUser ); + expect( token ).notToBeEmpty(); + } + ); - it( "can send challenges", function(){ - var results = provider.sendChallenge( mockUser ); - debug( results ); - expect( results.error ).toBeFalse( results.toString() ); - } ); - } ); + it( + "can send challenges", + () => { + var results = provider.sendChallenge( mockUser ); + debug( results ); + expect( results.error ).toBeFalse( results.toString() ); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/integration/widgets/CommentFormTest.cfc b/tests/specs/contentbox-web/contentbox/integration/widgets/CommentFormTest.cfc index 69246c3253..c33de29969 100644 --- a/tests/specs/contentbox-web/contentbox/integration/widgets/CommentFormTest.cfc +++ b/tests/specs/contentbox-web/contentbox/integration/widgets/CommentFormTest.cfc @@ -9,37 +9,51 @@ component extends="tests.resources.BaseTest" { /*********************************** LIFE CYCLE Methods ***********************************/ // executes before all suites+specs in the run() method - function beforeAll(){ + function beforeAll() { super.beforeAll(); widgetService = getInstance( "widgetService@contentbox" ); - cbHelper = getInstance( "CBHelper@contentbox" ); + cbHelper = getInstance( "CBHelper@contentbox" ); cbHelper.prepareUIRequest(); } /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ - describe( "Comment Form Widget", function(){ - beforeEach( function( currentSpec ){ - widget = widgetService.getWidget( "CommentForm" ); - } ); - - it( "can render a form with no content object passed", function(){ - var r = widget.renderIt( "" ); - expect( r.len() ).toBeGT( 0 ); - } ); - - it( "can render a form with an invalid slug", function(){ - var r = widget.renderIt( "bogus" ); - expect( r ).toInclude( "bogus was not found, cannot generate comment form" ); - } ); - - it( "can render a form with an valid slug", function(){ - var r = widget.renderIt( "support" ); - expect( r ).toInclude( "
      { + beforeEach( + ( currentSpec ) => { + widget = widgetService.getWidget( "CommentForm" ); + } + ); + + it( + "can render a form with no content object passed", + () => { + var r = widget.renderIt( "" ); + expect( r.len() ).toBeGT( 0 ); + } + ); + + it( + "can render a form with an invalid slug", + () => { + var r = widget.renderIt( "bogus" ); + expect( r ).toInclude( "bogus was not found, cannot generate comment form" ); + } + ); + + it( + "can render a form with an valid slug", + () => { + var r = widget.renderIt( "support" ); + expect( r ).toInclude( " { + beforeEach( + ( currentSpec ) => { + widget = widgetService.getWidget( "ContentStore" ); + } + ); + + it( + "can get valid content store items", + () => { + var r = widget.renderIt( "foot" ); + expect( r.len() ).toBeGT( 0 ); + } + ); + + it( + "can get invalid content store items with an exception", + () => { + expect( () => { + widget.renderIt( "invalid" ); + } ).toThrow(); + } + ); + + it( + "can get invalid content with a default value", + () => { + var r = widget.renderIt( "invalid", "" ); + expect( r ).toBe( "" ); + } + ); + + it( + "can get expired content with a default value of empty", + () => { + var r = widget.renderIt( "my-expired-content-store" ); + expect( r ).toBe( "" ); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/comments/CommentsServiceTest.cfc b/tests/specs/contentbox-web/contentbox/unit/comments/CommentsServiceTest.cfc index 0ce5cb1db6..1b902b5294 100755 --- a/tests/specs/contentbox-web/contentbox/unit/comments/CommentsServiceTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/comments/CommentsServiceTest.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -6,75 +6,107 @@ */ component extends="tests.resources.BaseTest" { - function run( testResults, testBox ){ + function run( testResults, testBox ) { // all your suites go here. - describe( "Comment Service", function(){ - beforeEach( function( currentSpec ){ - // Capture the request so the debugger can track our data. since we are in unit mode. - getController().getRequestService().requestCapture(); - commentService = getInstance( "CommentService@contentbox" ); - } ); + describe( + "Comment Service", + () => { + beforeEach( + ( currentSpec ) => { + // Capture the request so the debugger can track our data. since we are in unit mode. + getController().getRequestService().requestCapture(); + commentService = getInstance( "CommentService@contentbox" ); + } + ); - it( "can get approved comment count", function(){ - var r = commentService.getApprovedCount(); - expect( r ).toBeGT( 0 ); - } ); + it( + "can get approved comment count", + () => { + var r = commentService.getApprovedCount(); + expect( r ).toBeGT( 0 ); + } + ); - it( "can get unapproved comment count", function(){ - var r = commentService.getUnApprovedCount(); - expect( r ).toBeGT( 0 ); - } ); + it( + "can get unapproved comment count", + () => { + var r = commentService.getUnApprovedCount(); + expect( r ).toBeGT( 0 ); + } + ); - describe( "Approved Comment Finders", function(){ - it( "cand find all", function(){ - var r = commentService.findAllApproved(); - expect( r.count ).toBeGT( 0 ); - } ); - it( "can find by content ID", function(){ - var r = commentService.findAllApproved( contentID = "779cd806-a444-11eb-ab6f-0290cc502ae3" ); - expect( r.count ).toBe( 0 ); + describe( + "Approved Comment Finders", + () => { + it( + "cand find all", + () => { + var r = commentService.findAllApproved(); + expect( r.count ).toBeGT( 0 ); + } + ); + it( + "can find by content ID", + () => { + var r = commentService.findAllApproved( contentID = "779cd806-a444-11eb-ab6f-0290cc502ae3" ); + expect( r.count ).toBe( 0 ); - var r = commentService.findAllApproved( contentID = "779cd18a-a444-11eb-ab6f-0290cc502ae3" ); - expect( r.count ).toBeGT( 0 ); - } ); - it( "can find by content types", function(){ - var r = commentService.findAllApproved( contentType = "invalid" ); - expect( r.count ).toBe( 0 ); + var r = commentService.findAllApproved( contentID = "779cd18a-a444-11eb-ab6f-0290cc502ae3" ); + expect( r.count ).toBeGT( 0 ); + } + ); + it( + "can find by content types", + () => { + var r = commentService.findAllApproved( contentType = "invalid" ); + expect( r.count ).toBe( 0 ); - var r = commentService.findAllApproved( contentType = "Entry" ); - expect( r.count ).toBeGT( 0 ); - } ); - } ); + var r = commentService.findAllApproved( contentType = "Entry" ); + expect( r.count ).toBeGT( 0 ); + } + ); + } + ); - it( "can do comment searching by parameters", function(){ - // test get all - var r = commentService.search(); - expect( r.count ).toBeGT( 0 ); + it( + "can do comment searching by parameters", + () => { + // test get all + var r = commentService.search(); + expect( r.count ).toBeGT( 0 ); - // test any approved - var r = commentService.search( isApproved = "any" ); - expect( r.count ).toBeGT( 0 ); + // test any approved + var r = commentService.search( isApproved = "any" ); + expect( r.count ).toBeGT( 0 ); - var r = commentService.search( isApproved = false ); - expect( r.count ).toBeGTE( 1 ); + var r = commentService.search( isApproved = false ); + expect( r.count ).toBeGTE( 1 ); - var r = commentService.search( contentID = "779cd234-a444-11eb-ab6f-0290cc502ae3" ); - expect( r.count ).toBeGT( 0 ); + var r = commentService.search( contentID = "779cd234-a444-11eb-ab6f-0290cc502ae3" ); + expect( r.count ).toBeGT( 0 ); - // disjunction with content - var r = commentService.search( contentID = "779cd234-a444-11eb-ab6f-0290cc502ae3", search = "awesome" ); - expect( r.count ).toBeGTE( 1 ); - // disjunction with author - var r = commentService.search( contentID = "779cd234-a444-11eb-ab6f-0290cc502ae3", search = "luis" ); - expect( r.count ).toBeGTE( 1 ); - // disjunction with authorEmail - var r = commentService.search( - contentID = "779cd234-a444-11eb-ab6f-0290cc502ae3", - search = "lmajano@gmail.com" + // disjunction with content + var r = commentService.search( + contentID = "779cd234-a444-11eb-ab6f-0290cc502ae3", + search = "awesome" + ); + expect( r.count ).toBeGTE( 1 ); + // disjunction with author + var r = commentService.search( + contentID = "779cd234-a444-11eb-ab6f-0290cc502ae3", + search = "luis" + ); + expect( r.count ).toBeGTE( 1 ); + // disjunction with authorEmail + var r = commentService.search( + contentID = "779cd234-a444-11eb-ab6f-0290cc502ae3", + search = "lmajano@gmail.com" + ); + expect( r.count ).toBeGTE( 1 ); + } ); - expect( r.count ).toBeGTE( 1 ); - } ); - } ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/content/BaseContentTest.cfc b/tests/specs/contentbox-web/contentbox/unit/content/BaseContentTest.cfc index 19885b7d5c..cb63d54a28 100644 --- a/tests/specs/contentbox-web/contentbox/unit/content/BaseContentTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/content/BaseContentTest.cfc @@ -9,49 +9,60 @@ component extends="tests.resources.BaseTest" { /*********************************** LIFE CYCLE Methods ***********************************/ // executes before all suites+specs in the run() method - function beforeAll(){ + function beforeAll() { super.beforeAll(); } // executes after all suites+specs in the run() method - function afterAll(){ + function afterAll() { super.afterAll(); } /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ - describe( "Base Content", function(){ - beforeEach( function( currentSpec ){ - model = getInstance( "BaseContent@contentbox" ); - } ); - - it( "can add expired data time combinations", function(){ - // Test 1: empty - model.setExpireDate( "" ); - model.addExpiredTime( "11", "00" ); - expect( model.getExpireDate() ).toBe( "" ); - - // Test 2: Valid - var cDate = dateFormat( now(), "mm/dd/yyyy" ); - model.setExpireDate( cDate ); - model.addExpiredTime( "11", "00" ); - expect( model.getExpireDate() ).toBe( cDate & " " & timeFormat( "11:00", "hh:MM tt" ) ); - } ); - - it( "can add published date time combinations", function(){ - // Test 1: empty - model.setPublishedDate( "" ); - model.addPublishedTime( "11", "00" ); - expect( model.getPublishedDate() ).toBe( "" ); - - // Test 2: Valid - var cDate = dateFormat( now(), "mm/dd/yyyy" ); - model.setPublishedDate( cDate ); - model.addPublishedTime( "11", "00" ); - expect( model.getPublishedDate() ).toBe( cDate & " " & timeFormat( "11:00", "hh:MM tt" ) ); - } ); - } ); + function run( testResults, testBox ) { + describe( + "Base Content", + () => { + beforeEach( + ( currentSpec ) => { + model = getInstance( "BaseContent@contentbox" ); + } + ); + + it( + "can add expired data time combinations", + () => { + // Test 1: empty + model.setExpireDate( "" ); + model.addExpiredTime( "11", "00" ); + expect( model.getExpireDate() ).toBe( "" ); + + // Test 2: Valid + var cDate = dateFormat( now(), "mm/dd/yyyy" ); + model.setExpireDate( cDate ); + model.addExpiredTime( "11", "00" ); + expect( model.getExpireDate() ).toBe( cDate & " " & timeFormat( "11:00", "hh:MM tt" ) ); + } + ); + + it( + "can add published date time combinations", + () => { + // Test 1: empty + model.setPublishedDate( "" ); + model.addPublishedTime( "11", "00" ); + expect( model.getPublishedDate() ).toBe( "" ); + + // Test 2: Valid + var cDate = dateFormat( now(), "mm/dd/yyyy" ); + model.setPublishedDate( cDate ); + model.addPublishedTime( "11", "00" ); + expect( model.getPublishedDate() ).toBe( cDate & " " & timeFormat( "11:00", "hh:MM tt" ) ); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/content/CategoryTest.cfc b/tests/specs/contentbox-web/contentbox/unit/content/CategoryTest.cfc index 77bf2fd68d..fec0ecec62 100644 --- a/tests/specs/contentbox-web/contentbox/unit/content/CategoryTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/content/CategoryTest.cfc @@ -4,43 +4,59 @@ * www.ortussolutions.com/products/contentbox * --- */ -component extends="tests.resources.BaseTest" autowire="true" { - +component extends ="tests.resources.BaseTest" autowire="true" { property name="categoryService" inject="categoryService@contentbox"; - function run( testResults, testBox ){ - describe( "Categories", function(){ - beforeEach( function( currentSpec ){ - model = categoryService.new( { category : "unittest", slug : "unittest" } ); - } ); + function run( testResults, testBox ) { + describe( + "Categories", + () => { + beforeEach( + ( currentSpec ) => { + model = categoryService.new( { category: "unittest", slug: "unittest" } ); + } + ); - it( "can produce a memento", function(){ - var memento = model.getMemento(); - expect( memento ) - .tobeStruct() - .toHaveKey( "categoryID" ) - .toHaveKey( "category" ) - .toHaveKey( "slug" ); - } ); + it( + "can produce a memento", + () => { + var memento = model.getMemento(); + expect( memento ) + .tobeStruct() + .toHaveKey( "categoryID" ) + .toHaveKey( "category" ) + .toHaveKey( "slug" ); + } + ); - it( "can get published pages count", function(){ - var thisCategory = categoryService.findBySlug( "coldbox" ); - var count = thisCategory.getNumberOfPublishedPages(); - expect( count ).toBeGTE( 1 ); - } ); + it( + "can get published pages count", + () => { + var thisCategory = categoryService.findBySlug( "coldbox" ); + var count = thisCategory.getNumberOfPublishedPages(); + expect( count ).toBeGTE( 1 ); + } + ); - it( "can get published entries count", function(){ - var thisCategory = categoryService.findBySlug( "coldfusion" ); - var count = thisCategory.getNumberOfPublishedEntries(); - expect( count ).toBeGTE( 1 ); - } ); + it( + "can get published entries count", + () => { + var thisCategory = categoryService.findBySlug( "coldfusion" ); + var count = thisCategory.getNumberOfPublishedEntries(); + expect( count ).toBeGTE( 1 ); + } + ); - it( "can get published content store count", function(){ - var thisCategory = categoryService.findBySlug( "coldfusion" ); - var count = thisCategory.getNumberOfPublishedContentStore(); - expect( count ).toBeGTE( 1 ); - } ); - } ); + it( + "can get published content store count", + () => { + var thisCategory = categoryService.findBySlug( "coldfusion" ); + var count = thisCategory.getNumberOfPublishedContentStore(); + expect( count ).toBeGTE( 1 ); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/content/ContentStoreServiceTest.cfc b/tests/specs/contentbox-web/contentbox/unit/content/ContentStoreServiceTest.cfc index 3b18b5dfe9..a039c6795a 100755 --- a/tests/specs/contentbox-web/contentbox/unit/content/ContentStoreServiceTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/content/ContentStoreServiceTest.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -9,35 +9,43 @@ component extends="tests.resources.BaseTest" { /*********************************** LIFE CYCLE Methods ***********************************/ // executes before all suites+specs in the run() method - function beforeAll(){ + function beforeAll() { super.beforeAll(); } // executes after all suites+specs in the run() method - function afterAll(){ + function afterAll() { super.afterAll(); } /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ - describe( "Content Store Service", function(){ - beforeEach( function( currentSpec ){ - model = getInstance( "ContentStoreService@contentbox" ); - } ); - - it( "can search for content items", function(){ - // test get all - var r = model.search(); - expect( r.count ).toBeGT( 0 ); - - r = model.search( search = "Most greatest news" ); - expect( r.count ).toBeGT( 0 ); - - r = model.search( search = "sidebar" ); - expect( r.count ).toBeGT( 0 ); - } ); - } ); + function run( testResults, testBox ) { + describe( + "Content Store Service", + () => { + beforeEach( + ( currentSpec ) => { + model = getInstance( "ContentStoreService@contentbox" ); + } + ); + + it( + "can search for content items", + () => { + // test get all + var r = model.search(); + expect( r.count ).toBeGT( 0 ); + + r = model.search( search = "Most greatest news" ); + expect( r.count ).toBeGT( 0 ); + + r = model.search( search = "sidebar" ); + expect( r.count ).toBeGT( 0 ); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/content/ContentVersionServiceTest.cfc b/tests/specs/contentbox-web/contentbox/unit/content/ContentVersionServiceTest.cfc index 6aaa20dee2..eb98676049 100755 --- a/tests/specs/contentbox-web/contentbox/unit/content/ContentVersionServiceTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/content/ContentVersionServiceTest.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -9,28 +9,36 @@ component extends="tests.resources.BaseTest" { /*********************************** LIFE CYCLE Methods ***********************************/ // executes before all suites+specs in the run() method - function beforeAll(){ + function beforeAll() { super.beforeAll(); } // executes after all suites+specs in the run() method - function afterAll(){ + function afterAll() { super.afterAll(); } /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ - describe( "Content Version Service", function(){ - beforeEach( function( currentSpec ){ - model = getInstance( "ContentVersionService@contentbox" ); - } ); + function run( testResults, testBox ) { + describe( + "Content Version Service", + () => { + beforeEach( + ( currentSpec ) => { + model = getInstance( "ContentVersionService@contentbox" ); + } + ); - it( "can find related versions", function(){ - var r = model.findRelatedVersions( contentID = "779cd234-a444-11eb-ab6f-0290cc502ae3" ); - expect( r.count ).toBeGT( 0 ); - } ); - } ); + it( + "can find related versions", + () => { + var r = model.findRelatedVersions( contentID = "779cd234-a444-11eb-ab6f-0290cc502ae3" ); + expect( r.count ).toBeGT( 0 ); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/content/EntryServiceTest.cfc b/tests/specs/contentbox-web/contentbox/unit/content/EntryServiceTest.cfc index e313998dfd..2ac606f461 100755 --- a/tests/specs/contentbox-web/contentbox/unit/content/EntryServiceTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/content/EntryServiceTest.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -9,106 +9,127 @@ component extends="tests.resources.BaseTest" { /*********************************** LIFE CYCLE Methods ***********************************/ // executes before all suites+specs in the run() method - function beforeAll(){ + function beforeAll() { super.beforeAll(); } // executes after all suites+specs in the run() method - function afterAll(){ + function afterAll() { super.afterAll(); } /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ - describe( "Entry Services", function(){ - beforeEach( function( currentSpec ){ - model = getInstance( "EntryService@contentbox" ); - } ); - - it( "can get archives report", function(){ - var r = model.getArchiveReport(); - expect( arrayLen( r ) ).toBeGT( 0 ); - } ); - - it( "can get IDs by slug", function(){ - var r = model.getIDBySlug( "bogus" ); - expect( r ).toBe( "" ); - - var r = model.getIDBySlug( "this-is-just-awesome" ); - debug( r ); - } ); + function run( testResults, testBox ) { + describe( + "Entry Services", + () => { + beforeEach( + ( currentSpec ) => { + model = getInstance( "EntryService@contentbox" ); + } + ); - it( "can search for entries", function(){ - var r = model.search(); - expect( r.count ).toBeGT( 0 ); + it( + "can get archives report", + () => { + var r = model.getArchiveReport(); + expect( arrayLen( r ) ).toBeGT( 0 ); + } + ); - var r = model.search( isPublished = false ); - expect( r.count ).toBe( 2 ); + it( + "can get IDs by slug", + () => { + var r = model.getIDBySlug( "bogus" ); + expect( r ).toBe( "" ); - var r = model.search( isPublished = true ); - expect( r.count ).toBeGT( 0 ); + var r = model.getIDBySlug( "this-is-just-awesome" ); + debug( r ); + } + ); - var entries = entityLoad( "cbEntry" ); - var authorID = entries[ 1 ].getAuthor().getAuthorID(); - var r = model.search( author = authorID ); - expect( r.count ).toBeGT( 0 ); + it( + "can search for entries", + () => { + var r = model.search(); + expect( r.count ).toBeGT( 0 ); - // search - var r = model.search( search = "everybody" ); - expect( r.count ).toBeGT( 0 ); + var r = model.search( isPublished = false ); + expect( r.count ).toBe( 2 ); - // no categories - var r = model.search( category = "none" ); - expect( r.count ).toBeGT( 0 ); + var r = model.search( isPublished = true ); + expect( r.count ).toBeGT( 0 ); - // no categories - var r = model.search( category = "786a98cc-a444-11eb-ab6f-0290cc502ae3" ); - expect( r.count ).toBe( 0 ); - } ); + var entries = entityLoad( "cbEntry" ); + var authorID = entries[ 1 ].getAuthor().getAuthorID(); + var r = model.search( author = authorID ); + expect( r.count ).toBeGT( 0 ); - it( "can find published entries by published dates", function(){ - var entry = entityLoad( "cbEntry" )[ 1 ]; + // search + var r = model.search( search = "everybody" ); + expect( r.count ).toBeGT( 0 ); - // nothing - var r = model.findPublishedEntriesByDate( year = 2000 ); - expect( arrayLen( r.entries ) ).toBeFalse( "Year 2000" ); + // no categories + var r = model.search( category = "none" ); + expect( r.count ).toBeGT( 0 ); - // year - var r = model.findPublishedEntriesByDate( year = dateFormat( entry.getPublishedDate(), "yyyy" ) ); - expect( arrayLen( r.entries ) ).toBeGTE( 1, "Using entry publish year" ); + // no categories + var r = model.search( category = "786a98cc-a444-11eb-ab6f-0290cc502ae3" ); + expect( r.count ).toBe( 0 ); + } + ); - // year + Month - var r = model.findPublishedEntriesByDate( - year = dateFormat( entry.getPublishedDate(), "yyyy" ), - month = dateFormat( entry.getPublishedDate(), "mm" ) + it( + "can find published entries by published dates", + () => { + var entry = entityLoad( "cbEntry" )[ 1 ]; + + // nothing + var r = model.findPublishedEntriesByDate( year = 2000 ); + expect( arrayLen( r.entries ) ).toBeFalse( "Year 2000" ); + + // year + var r = model.findPublishedEntriesByDate( year = dateFormat( entry.getPublishedDate(), + "yyyy" ) ); + expect( arrayLen( r.entries ) ).toBeGTE( 1, "Using entry publish year" ); + + // year + Month + var r = model.findPublishedEntriesByDate( + year = dateFormat( entry.getPublishedDate(), "yyyy" ), + month = dateFormat( entry.getPublishedDate(), "mm" ) + ); + expect( arrayLen( r.entries ) ).toBeGTE( 1, "Using entry publish year and month" ); + + // year + Month + day + var r = model.findPublishedEntriesByDate( + year = dateFormat( entry.getPublishedDate(), "yyyy" ), + month = dateFormat( entry.getPublishedDate(), "mm" ), + day = dateFormat( entry.getPublishedDate(), "dd" ) + ); + expect( arrayLen( r.entries ) ).toBeGTE( 1, "Using entry publish year, month, and day" ); + } ); - expect( arrayLen( r.entries ) ).toBeGTE( 1, "Using entry publish year and month" ); - // year + Month + day - var r = model.findPublishedEntriesByDate( - year = dateFormat( entry.getPublishedDate(), "yyyy" ), - month = dateFormat( entry.getPublishedDate(), "mm" ), - day = dateFormat( entry.getPublishedDate(), "dd" ) + it( + "can find published entries by criteria", + () => { + var r = model.findPublishedContent(); + expect( r.count ).toBeGT( 0 ); + + // categories + var r = model.findPublishedContent( category = "software" ); + expect( r.count ).toBe( 0 ); + var r = model.findPublishedContent( category = "ColdFusion" ); + expect( r.count ).toBeGTE( 1 ); + + // search + var r = model.findPublishedContent( search = "first" ); + expect( r.count ).toBeGT( 0 ); + } ); - expect( arrayLen( r.entries ) ).toBeGTE( 1, "Using entry publish year, month, and day" ); - } ); - - it( "can find published entries by criteria", function(){ - var r = model.findPublishedContent(); - expect( r.count ).toBeGT( 0 ); - - // categories - var r = model.findPublishedContent( category = "software" ); - expect( r.count ).toBe( 0 ); - var r = model.findPublishedContent( category = "ColdFusion" ); - expect( r.count ).toBeGTE( 1 ); - - // search - var r = model.findPublishedContent( search = "first" ); - expect( r.count ).toBeGT( 0 ); - } ); - } ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/content/PageServiceTest.cfc b/tests/specs/contentbox-web/contentbox/unit/content/PageServiceTest.cfc index c3c60e34d7..ffc78113ca 100755 --- a/tests/specs/contentbox-web/contentbox/unit/content/PageServiceTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/content/PageServiceTest.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -9,67 +9,78 @@ component extends="tests.resources.BaseTest" { /*********************************** LIFE CYCLE Methods ***********************************/ // executes before all suites+specs in the run() method - function beforeAll(){ + function beforeAll() { super.beforeAll(); } // executes after all suites+specs in the run() method - function afterAll(){ + function afterAll() { super.afterAll(); } /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ - describe( "Page Services", function(){ - beforeEach( function( currentSpec ){ - model = getInstance( "PageService@contentbox" ); - } ); + function run( testResults, testBox ) { + describe( + "Page Services", + () => { + beforeEach( + ( currentSpec ) => { + model = getInstance( "PageService@contentbox" ); + } + ); - it( "can search for entries", function(){ - var r = model.search(); - expect( r.count ).toBeGT( 0 ); + it( + "can search for entries", + () => { + var r = model.search(); + expect( r.count ).toBeGT( 0 ); - var r = model.search( isPublished = false ); - expect( r.count ).toBeGT( 1 ); - var r = model.search( isPublished = true ); - expect( r.count ).toBeGT( 0 ); + var r = model.search( isPublished = false ); + expect( r.count ).toBeGT( 1 ); + var r = model.search( isPublished = true ); + expect( r.count ).toBeGT( 0 ); - var pages = entityLoad( "cbPage" ); - var authorID = pages[ 1 ].getAuthor().getAuthorID(); - var r = model.search( author = authorID ); - expect( r.count ).toBeGT( 0 ); + var pages = entityLoad( "cbPage" ); + var authorID = pages[ 1 ].getAuthor().getAuthorID(); + var r = model.search( author = authorID ); + expect( r.count ).toBeGT( 0 ); - // search - var r = model.search( search = "products" ); - expect( r.count ).toBeGT( 0 ); + // search + var r = model.search( search = "products" ); + expect( r.count ).toBeGT( 0 ); - // parent - var r = model.search( parent = "" ); - expect( r.count ).toBeGT( 0 ); - var r = model.search( parent = "1" ); - expect( r.count ).toBe( 0 ); - } ); + // parent + var r = model.search( parent = "" ); + expect( r.count ).toBeGT( 0 ); + var r = model.search( parent = "1" ); + expect( r.count ).toBe( 0 ); + } + ); - it( "cand find published pages", function(){ - var r = model.findPublishedContent(); - expect( r.count ).toBeGT( 0 ); + it( + "cand find published pages", + () => { + var r = model.findPublishedContent(); + expect( r.count ).toBeGT( 0 ); - // search - var r = model.findPublishedContent( searchTerm = "products" ); - expect( r.count ).toBeGT( 0 ); + // search + var r = model.findPublishedContent( searchTerm = "products" ); + expect( r.count ).toBeGT( 0 ); - // parent - var r = model.findPublishedContent( parent = "" ); - expect( r.count ).toBeGT( 0 ); - var r = model.findPublishedContent( parent = "1" ); - expect( r.count ).toBe( 0 ); + // parent + var r = model.findPublishedContent( parent = "" ); + expect( r.count ).toBeGT( 0 ); + var r = model.findPublishedContent( parent = "1" ); + expect( r.count ).toBe( 0 ); - // search - var r = model.findPublishedContent( showInMenu = true ); - expect( r.count ).toBeGT( 0 ); - } ); - } ); + // search + var r = model.findPublishedContent( showInMenu = true ); + expect( r.count ).toBeGT( 0 ); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/content/RelocationTest.cfc b/tests/specs/contentbox-web/contentbox/unit/content/RelocationTest.cfc index f06f8c782a..13a238dfb3 100644 --- a/tests/specs/contentbox-web/contentbox/unit/content/RelocationTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/content/RelocationTest.cfc @@ -4,50 +4,69 @@ * www.ortussolutions.com/products/contentbox * --- */ -component extends="tests.resources.BaseTest" autowire="true" { - +component extends ="tests.resources.BaseTest" autowire="true" { property name="relocationService" inject="RelocationService@contentbox"; + property name="siteService" inject="SiteService@contentbox"; - function run( testResults, testBox ){ - describe( "Relocations", function(){ - beforeEach( function( currentSpec ){ - model = relocationService.new( { target : "unittest", slug : "unittest" } ); - } ); + function run( testResults, testBox ) { + describe( + "Relocations", + () => { + beforeEach( + ( currentSpec ) => { + model = relocationService.new( { target: "unittest", slug: "unittest" } ); + } + ); - it( "can produce a memento", function(){ - var memento = model.getMemento(); - expect( memento ) - .tobeStruct() - .toHaveKey( "relocationID" ) - .toHaveKey( "target" ) - .toHaveKey( "createdDate" ) - .toHaveKey( "slug" ) - .toHaveKey( "relatedContent" ); - } ); + it( + "can produce a memento", + () => { + var memento = model.getMemento(); + expect( memento ) + .tobeStruct() + .toHaveKey( "relocationID" ) + .toHaveKey( "target" ) + .toHaveKey( "createdDate" ) + .toHaveKey( "slug" ) + .toHaveKey( "relatedContent" ); + } + ); - it( "will remove leading and trailing slashes from new relocation slugs", function(){ - model.setSlug( "/unittest/" ); - expect( model.getSlug() ).toBe( "unittest" ); - } ); + it( + "will remove leading and trailing slashes from new relocation slugs", + () => { + model.setSlug( "/unittest/" ); + expect( model.getSlug() ).toBe( "unittest" ); + } + ); - it( "Can search for a relocation by siteId", function(){ - var defaultSite = siteService.findBySlug( "default" ); - var response = relocationService.search( siteID = defaultSite.getSiteId() ); - expect( response ).toHaveKey( "relocations" ); - expect( response.relocations ).toBeArray(); - response.relocations.each( function( r ){ - expect( r.getSite().getSiteID() ).toBe( defaultSite.getSiteId() ); - } ); - } ); + it( + "Can search for a relocation by siteId", + () => { + var defaultSite = siteService.findBySlug( "default" ); + var response = relocationService.search( siteID = defaultSite.getSiteId() ); + expect( response ).toHaveKey( "relocations" ); + expect( response.relocations ).toBeArray(); + response.relocations.each( + ( r ) => { + expect( r.getSite().getSiteID() ).toBe( defaultSite.getSiteId() ); + } + ); + } + ); - it( "Can search for a relocation by a partial value of the slug", function(){ - var defaultSite = siteService.findBySlug( "default" ); - var response = relocationService.search( search = "unittest" ); - expect( response ).toHaveKey( "relocations" ); - expect( response.relocations ).toBeArray(); - } ); - } ); + it( + "Can search for a relocation by a partial value of the slug", + () => { + var defaultSite = siteService.findBySlug( "default" ); + var response = relocationService.search( search = "unittest" ); + expect( response ).toHaveKey( "relocations" ); + expect( response.relocations ).toBeArray(); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/importers/ContentBoxImporterSpec.cfc b/tests/specs/contentbox-web/contentbox/unit/importers/ContentBoxImporterSpec.cfc index 37873233e4..d53f6d291a 100644 --- a/tests/specs/contentbox-web/contentbox/unit/importers/ContentBoxImporterSpec.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/importers/ContentBoxImporterSpec.cfc @@ -6,39 +6,50 @@ */ component extends="tests.resources.BaseTest" { - function beforeAll(){ + function beforeAll() { super.beforeAll(); setup(); contentboxImporter = getInstance( "ContentBoxImporter@contentbox" ); } - function run( testResults, testBox ){ - describe( "ContentBox Importer Service", function(){ - it( "can be created", function(){ - expect( contentboxImporter ).toBeComponent(); - } ); + function run( testResults, testBox ) { + describe( + "ContentBox Importer Service", + () => { + it( + "can be created", + () => { + expect( contentboxImporter ).toBeComponent(); + } + ); - it( "can import settings", function(){ - withRollback( () => { - var importData = deserializeJSON( - fileRead( expandPath( "/tests/resources/exports/setting.json" ) ) - ); - var importLog = createObject( "java", "java.lang.StringBuilder" ).init( "" ); + it( + "can import settings", + () => { + withRollback( + () => { + var importData = deserializeJSON( + fileRead( expandPath( "/tests/resources/exports/setting.json" ) ) + ); + var importLog = createObject( "java", "java.lang.StringBuilder" ).init( "" ); - var output = getInstance( "settingService@contentbox" ).importFromData( - importData: importData, - override : false, - importLog : importLog - ); + var output = getInstance( "settingService@contentbox" ).importFromData( + importData = importData, + override = false, + importLog = importLog + ); - expect( output ).notToBeEmpty(); - expect( output ).toInclude( - "No settings imported as none where found or able to be overriden from the import file." - ); - } ) - } ); - } ); + expect( output ).notToBeEmpty(); + expect( output ).toInclude( + "No settings imported as none where found or able to be overriden from the import file." + ); + } + ); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/media/MediaServiceTest.cfc b/tests/specs/contentbox-web/contentbox/unit/media/MediaServiceTest.cfc index 4ff093fd55..b21cd1098e 100644 --- a/tests/specs/contentbox-web/contentbox/unit/media/MediaServiceTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/media/MediaServiceTest.cfc @@ -6,45 +6,68 @@ */ component extends="tests.resources.BaseTest" { - function run( testResults, testBox ){ - describe( "DB Search Adapter", function(){ - beforeEach( function( currentSpec ){ - setup(); - service = getInstance( "MediaService@contentbox" ).init( getWireBox() ); - } ); - - it( "can register and get providers", function(){ - var provider = service.getProvider( "CFContentMediaProvider" ); - expect( provider ).toBeComponent(); - assertEquals( "CFContentMediaProvider", provider.getName() ); - assertEquals( "CF Content Media Provider", provider.getDisplayName() ); - } ); - - it( "can get the default provider", function(){ - assertEquals( "CFContentMediaProvider", service.getDefaultProviderName() ); - } ); - - it( "can unregister a provider", function(){ - service.unregisterProvider( "CFContentMediaProvider" ); - expect( service.getRegisteredProviders() ).notToInclude( "CFContentMediaProvider" ); - } ); - - it( "can get the registered providers map", function(){ - var map = service.getRegisteredProvidersMap(); - debug( map ); - expect( map ).toBeArray().notToBeEmpty(); - } ); - - it( "can get the path to the core media root", function(){ - var path = service.getCoreMediaRoot(); - expect( path ).toInclude( "/contentbox-custom/_content" ); - } ); - - it( "can get the absolute path to the core media root", function(){ - var path = service.getCoreMediaRoot( true ); - expect( directoryExists( path ) ).toBeTrue(); - } ); - } ); + function run( testResults, testBox ) { + describe( + "DB Search Adapter", + () => { + beforeEach( + ( currentSpec ) => { + setup(); + service = getInstance( "MediaService@contentbox" ).init( getWireBox() ); + } + ); + + it( + "can register and get providers", + () => { + var provider = service.getProvider( "CFContentMediaProvider" ); + expect( provider ).toBeComponent(); + assertEquals( "CFContentMediaProvider", provider.getName() ); + assertEquals( "CF Content Media Provider", provider.getDisplayName() ); + } + ); + + it( + "can get the default provider", + () => { + assertEquals( "CFContentMediaProvider", service.getDefaultProviderName() ); + } + ); + + it( + "can unregister a provider", + () => { + service.unregisterProvider( "CFContentMediaProvider" ); + expect( service.getRegisteredProviders() ).notToInclude( "CFContentMediaProvider" ); + } + ); + + it( + "can get the registered providers map", + () => { + var map = service.getRegisteredProvidersMap(); + debug( map ); + expect( map ).toBeArray().notToBeEmpty(); + } + ); + + it( + "can get the path to the core media root", + () => { + var path = service.getCoreMediaRoot(); + expect( path ).toInclude( "/contentbox-custom/_content" ); + } + ); + + it( + "can get the absolute path to the core media root", + () => { + var path = service.getCoreMediaRoot( true ); + expect( directoryExists( path ) ).toBeTrue(); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/modules/ModuleServiceTest.cfc b/tests/specs/contentbox-web/contentbox/unit/modules/ModuleServiceTest.cfc index e3a4ddcbe1..b3cbca9035 100755 --- a/tests/specs/contentbox-web/contentbox/unit/modules/ModuleServiceTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/modules/ModuleServiceTest.cfc @@ -9,70 +9,97 @@ component extends="tests.resources.BaseTest" { /*********************************** LIFE CYCLE Methods ***********************************/ // executes before all suites+specs in the run() method - function beforeAll(){ + function beforeAll() { super.beforeAll(); } // executes after all suites+specs in the run() method - function afterAll(){ + function afterAll() { super.afterAll(); } /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ - describe( "Module Services", function(){ - aroundEach( function( spec, suite ){ - ormClearSession(); - ormCloseSession(); - try { - // Make sure we always rollback - transaction { - arguments.spec.body(); + function run( testResults, testBox ) { + describe( + "Module Services", + () => { + aroundEach( + ( spec, suite ) => { + ormClearSession(); + ormCloseSession(); + try { + // Make sure we always rollback + transaction { + arguments.spec.body(); + } + } catch (any e) { + transactionRollback(); + rethrow; + } } - } catch ( any e ) { - transactionRollback(); - rethrow; - } - } ); + ); - beforeEach( function( currentSpec ){ - model = getInstance( "ModuleService@contentbox" ); - } ); - - it( "can populate a module", function(){ - var module = entityNew( "cbModule" ); - var mock = createStub(); - mock.title = mock.description = mock.author = mock.webURL = mock.forgeboxslug = mock.entryPoint = "unit"; - mock.version = "1.0.0"; + beforeEach( + ( currentSpec ) => { + model = getInstance( "ModuleService@contentbox" ); + } + ); - model.populateModule( module, mock ); - expect( module.getVersion() ).toBe( "1.0.0" ); - expect( module.getAuthor() ).toBe( "unit" ); - } ); + it( + "can populate a module", + () => { + var module = entityNew( "cbModule" ); + var mock = createStub(); + mock.title = mock.description = mock.author = mock.webURL = mock.forgeboxslug = mock.entryPoint = "unit"; + mock.version = "1.0.0"; - it( "can find modules", function(){ - var r = model.findModules(); - expect( r.count ).toBeGTE( 1 ); - } ); + model.populateModule( module, mock ); + expect( module.getVersion() ).toBe( "1.0.0" ); + expect( module.getAuthor() ).toBe( "unit" ); + } + ); + it( + "can find modules", + () => { + var r = model.findModules(); + expect( r.count ).toBeGTE( 1 ); + } + ); - story( "Find modules by entry point", function(){ - given( "an invalid entrypoint", function(){ - then( "it should return a new module", function(){ - var r = model.findModuleByEntryPoint( "invalid" ); - expect( r.isLoaded() ).toBeFalse(); - } ); - } ); + story( + "Find modules by entry point", + () => { + given( + "an invalid entrypoint", + () => { + then( + "it should return a new module", + () => { + var r = model.findModuleByEntryPoint( "invalid" ); + expect( r.isLoaded() ).toBeFalse(); + } + ); + } + ); - given( "a valid entrypoint", function(){ - then( "it should return a new module", function(){ - var r = model.findModuleByEntryPoint( "HelloContentBox" ); - expect( r.isLoaded() ).toBeTrue(); - } ); - } ); - } ); - } ); + given( + "a valid entrypoint", + () => { + then( + "it should return a new module", + () => { + var r = model.findModuleByEntryPoint( "HelloContentBox" ); + expect( r.isLoaded() ).toBeTrue(); + } + ); + } + ); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/rss/RSSServiceTest.cfc b/tests/specs/contentbox-web/contentbox/unit/rss/RSSServiceTest.cfc index 5475c030d7..82f3c33171 100755 --- a/tests/specs/contentbox-web/contentbox/unit/rss/RSSServiceTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/rss/RSSServiceTest.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -6,20 +6,24 @@ */ component extends="tests.resources.BaseTest" skip { - function setup(){ + function setup() { super.setup(); mockSettingsService = prepareMock( getInstance( "SettingService@contentbox" ) ); - mockCBHelper = prepareMock( getInstance( "CBHelper@contentbox" ) ); - service = prepareMock( getInstance( "RSSService@contentbox" ) ); + mockCBHelper = prepareMock( getInstance( "CBHelper@contentbox" ) ); + service = prepareMock( getInstance( "RSSService@contentbox" ) ); service.$property( - "settingService", - "variables", - mockSettingsService - ); - service.$property( "CBHelper", "variables", mockCBHelper ); + "settingService", + "variables", + mockSettingsService + ); + service.$property( + "CBHelper", + "variables", + mockCBHelper + ); } - function testBuildCommentFeed(){ + function testBuildCommentFeed() { // mock cb mockCBHelper .$( "siteName", "Unit Test" ) @@ -33,7 +37,7 @@ component extends="tests.resources.BaseTest" skip { // Slug var b = entityLoad( "cbEntry" )[ 1 ]; - r = service.buildCommentFeed( slug = b.getSlug() ); + r = service.buildCommentFeed( slug = b.getSlug() ); assertTrue( isXML( r ) ); // ContentType @@ -41,8 +45,12 @@ component extends="tests.resources.BaseTest" skip { assertTrue( isXML( r ) ); } - function testBuildContentFeed(){ - getRequestContext().setValue( "CBENTRYPOINT", "http://localhost", true ); + function testBuildContentFeed() { + getRequestContext().setValue( + "CBENTRYPOINT", + "http://localhost", + true + ); // mock cb mockCBHelper .$( "siteName", "Unit Test" ) @@ -60,8 +68,12 @@ component extends="tests.resources.BaseTest" skip { assertTrue( isXML( r ) ); } - function testBuildEntryFeed(){ - getRequestContext().setValue( "CBENTRYPOINT", "http://localhost", true ); + function testBuildEntryFeed() { + getRequestContext().setValue( + "CBENTRYPOINT", + "http://localhost", + true + ); // mock cb mockCBHelper .$( "siteName", "Unit Test" ) @@ -79,8 +91,12 @@ component extends="tests.resources.BaseTest" skip { assertTrue( isXML( r ) ); } - function testbuildPageFeed(){ - getRequestContext().setValue( "CBENTRYPOINT", "http://localhost", true ); + function testbuildPageFeed() { + getRequestContext().setValue( + "CBENTRYPOINT", + "http://localhost", + true + ); // mock cb mockCBHelper .$( "siteName", "Unit Test" ) @@ -98,4 +114,4 @@ component extends="tests.resources.BaseTest" skip { assertTrue( isXML( r ) ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/search/DBSearchTest.cfc b/tests/specs/contentbox-web/contentbox/unit/search/DBSearchTest.cfc index a4f439bec9..2ed0d03f75 100755 --- a/tests/specs/contentbox-web/contentbox/unit/search/DBSearchTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/search/DBSearchTest.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -8,56 +8,73 @@ component extends="tests.resources.BaseTest" { /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ - describe( "DB Search Adapter", function(){ - beforeEach( function( currentSpec ){ - setup(); - model = getInstance( "DBSearch@contentbox" ); - } ); - - it( "can do search with no results", function(){ - var r = model.search( searchTerm = "bogus pocus" ); - - expect( r.getTotal() ).toBe( 0 ); - expect( r.getSearchTerm() ).toBe( "bogus pocus" ); - expect( r.getResults() ).toBeArray(); - expect( r.getError() ).toBeFalse(); - } ); - - it( "can do search with results", function(){ - var r = model.search( searchTerm = "Support" ); - - expect( r.getTotal() ).toBeGT( 0 ); - expect( r.getSearchTerm() ).toBe( "Support" ); - expect( r.getResults() ).toBeArray(); - expect( r.getResults().size() ).toBeGT( 0 ); - expect( r.getError() ).toBeFalse(); - } ); - - it( "can render search results", function(){ - // setup - var r = model.search( searchTerm = "Support" ); - var prc = getRequestContext().getPrivateCollection(); - prc.cbEntryPoint = "/"; - prc.cbSettings = {}; - - var rendering = model.renderSearchWithResults( r ); - // debug( rendering ); - expect( rendering ).toInclude( "Support" ).toInclude( "searchResults" ); - } ); - - it( "can render search with no results", function(){ - // setup - var r = model.search( searchTerm = "bogus pocus" ); - var prc = getRequestContext().getPrivateCollection(); - prc.cbEntryPoint = "/"; - prc.cbSettings = {}; - - var rendering = model.renderSearchWithResults( r ); - // debug( rendering ); - expect( rendering ).toInclude( "searchResults" ).toInclude( "0" ); - } ); - } ); + function run( testResults, testBox ) { + describe( + "DB Search Adapter", + () => { + beforeEach( + ( currentSpec ) => { + setup(); + model = getInstance( "DBSearch@contentbox" ); + } + ); + + it( + "can do search with no results", + () => { + var r = model.search( searchTerm = "bogus pocus" ); + + expect( r.getTotal() ).toBe( 0 ); + expect( r.getSearchTerm() ).toBe( "bogus pocus" ); + expect( r.getResults() ).toBeArray(); + expect( r.getError() ).toBeFalse(); + } + ); + + it( + "can do search with results", + () => { + var r = model.search( searchTerm = "Support" ); + + expect( r.getTotal() ).toBeGT( 0 ); + expect( r.getSearchTerm() ).toBe( "Support" ); + expect( r.getResults() ).toBeArray(); + expect( r.getResults().size() ).toBeGT( 0 ); + expect( r.getError() ).toBeFalse(); + } + ); + + it( + "can render search results", + () => { + // setup + var r = model.search( searchTerm = "Support" ); + var prc = getRequestContext().getPrivateCollection(); + prc.cbEntryPoint = "/"; + prc.cbSettings = {}; + + var rendering = model.renderSearchWithResults( r ); + // debug( rendering ); + expect( rendering ).toInclude( "Support" ).toInclude( "searchResults" ); + } + ); + + it( + "can render search with no results", + () => { + // setup + var r = model.search( searchTerm = "bogus pocus" ); + var prc = getRequestContext().getPrivateCollection(); + prc.cbEntryPoint = "/"; + prc.cbSettings = {}; + + var rendering = model.renderSearchWithResults( r ); + // debug( rendering ); + expect( rendering ).toInclude( "searchResults" ).toInclude( "0" ); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/search/SearchResultsTest.cfc b/tests/specs/contentbox-web/contentbox/unit/search/SearchResultsTest.cfc index 4c1dc6cc3f..13a2dc1d8f 100755 --- a/tests/specs/contentbox-web/contentbox/unit/search/SearchResultsTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/search/SearchResultsTest.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -6,35 +6,45 @@ */ component extends="tests.resources.BaseTest" { - function run( testResults, testBox ){ - describe( "Search Results", function(){ - beforeEach( function( currentSpec ){ - setup(); - model = getInstance( "SearchResults@contentbox" ); - } ); + function run( testResults, testBox ) { + describe( + "Search Results", + () => { + beforeEach( + ( currentSpec ) => { + setup(); + model = getInstance( "SearchResults@contentbox" ); + } + ); + it( + "can get the memento", + () => { + var results = model.getMemento(); + expect( results ).toBeStruct(); + } + ); - it( "can get the memento", function(){ - var results = model.getMemento(); - expect( results ).toBeStruct(); - } ); + it( + "can populate", + () => { + var r = { + results : [], + searchTime : getTickCount(), + total : 0, + metadata : { name: "luis", value: "awesome" }, + error : false, + errorMessages: [], + searchTerm : "luis" + }; - it( "can populate", function(){ - var r = { - results : [], - searchTime : getTickCount(), - total : 0, - metadata : { name : "luis", value : "awesome" }, - error : false, - errorMessages : [], - searchTerm : "luis" - }; - - model.populate( r ); - var m = model.getMemento(); - assertEquals( r, m ); - } ); - } ); + model.populate( r ); + var m = model.getMemento(); + assertEquals( r, m ); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/search/SearchServiceTest.cfc b/tests/specs/contentbox-web/contentbox/unit/search/SearchServiceTest.cfc index 2dfae3fe54..6c02285fb2 100755 --- a/tests/specs/contentbox-web/contentbox/unit/search/SearchServiceTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/search/SearchServiceTest.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -6,18 +6,26 @@ */ component extends="tests.resources.BaseTest" { - function run( testResults, testBox ){ - describe( "Search Service", function(){ - beforeEach( function( currentSpec ){ - setup(); - searchService = getInstance( "SearchService@contentbox" ); - } ); + function run( testResults, testBox ) { + describe( + "Search Service", + () => { + beforeEach( + ( currentSpec ) => { + setup(); + searchService = getInstance( "SearchService@contentbox" ); + } + ); - it( "can get the search adapter", function(){ - var adapter = searchService.getSearchAdapter(); - expect( adapter ).toBeComponent(); - } ); - } ); + it( + "can get the search adapter", + () => { + var adapter = searchService.getSearchAdapter(); + expect( adapter ).toBeComponent(); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/security/AuthorServiceTest.cfc b/tests/specs/contentbox-web/contentbox/unit/security/AuthorServiceTest.cfc index 2c9882a31e..93681b883d 100644 --- a/tests/specs/contentbox-web/contentbox/unit/security/AuthorServiceTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/security/AuthorServiceTest.cfc @@ -6,7 +6,7 @@ component extends="tests.resources.BaseTest" { /*********************************** LIFE CYCLE Methods ***********************************/ // executes before all suites+specs in the run() method - function beforeAll(){ + function beforeAll() { super.beforeAll(); setup(); authorService = getInstance( "authorService@contentbox" ); @@ -14,56 +14,83 @@ component extends="tests.resources.BaseTest" { /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ + function run( testResults, testBox ) { // all your suites go here. - describe( "Author Service", function(){ - it( "can search for authors with 2 factor auth status", function(){ - var results = authorService.search( twoFactorAuth = "true" ); - for ( var item in results.authors ) { - expect( item.getIs2FactorAuth() ).toBeTrue(); - } - } ); + describe( + "Author Service", + () => { + it( + "can search for authors with 2 factor auth status", + () => { + var results = authorService.search( twoFactorAuth = "true" ); + for ( var item in results.authors ) { + expect( item.getIs2FactorAuth() ).toBeTrue(); + } + } + ); - it( "can search for authors without 2 factor auth status", function(){ - var results = authorService.search( twoFactorAuth = "false" ); - for ( var item in results.authors ) { - expect( item.getIs2FactorAuth() ).toBeFalse(); - } - } ); + it( + "can search for authors without 2 factor auth status", + () => { + var results = authorService.search( twoFactorAuth = "false" ); + for ( var item in results.authors ) { + expect( item.getIs2FactorAuth() ).toBeFalse(); + } + } + ); - it( "can be created", function(){ - expect( isObject( authorService ) ).toBeTrue(); - } ); + it( + "can be created", + () => { + expect( isObject( authorService ) ).toBeTrue(); + } + ); - it( "can get status author reports", function(){ - var report = authorService.getStatusReport(); - expect( report ) - .toHaveKey( "active" ) - .toHaveKey( "deactivated" ) - .toHaveKey( "2FactorAuthEnabled" ) - .toHaveKey( "2FactorAuthDisabled" ); - } ); + it( + "can get status author reports", + () => { + var report = authorService.getStatusReport(); + expect( report ) + .toHaveKey( "active" ) + .toHaveKey( "deactivated" ) + .toHaveKey( "2FactorAuthEnabled" ) + .toHaveKey( "2FactorAuthDisabled" ); + } + ); - it( "can check for non existent usernames", function(){ - var results = authorService.usernameFound( "bogus" ); - expect( results ).toBeFalse(); - } ); + it( + "can check for non existent usernames", + () => { + var results = authorService.usernameFound( "bogus" ); + expect( results ).toBeFalse(); + } + ); - it( "can check for existent usernames", function(){ - var results = authorService.usernameFound( "lmajano" ); - expect( results ).toBeTrue(); - } ); + it( + "can check for existent usernames", + () => { + var results = authorService.usernameFound( "lmajano" ); + expect( results ).toBeTrue(); + } + ); - it( "can check for non existent emails", function(){ - var results = authorService.emailFound( "bogus" ); - expect( results ).toBeFalse(); - } ); + it( + "can check for non existent emails", + () => { + var results = authorService.emailFound( "bogus" ); + expect( results ).toBeFalse(); + } + ); - it( "can check for existent emails", function(){ - var results = authorService.emailFound( "lmajano@gmail.com" ); - expect( results ).toBeTrue(); - } ); - } ); + it( + "can check for existent emails", + () => { + var results = authorService.emailFound( "lmajano@gmail.com" ); + expect( results ).toBeTrue(); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/security/AuthorTest.cfc b/tests/specs/contentbox-web/contentbox/unit/security/AuthorTest.cfc index 49e835ef9e..5b403b620b 100755 --- a/tests/specs/contentbox-web/contentbox/unit/security/AuthorTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/security/AuthorTest.cfc @@ -8,64 +8,93 @@ component extends="tests.resources.BaseTest" { /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ - describe( "Author Suite", function(){ - beforeEach( function( currentSpec ){ - model = entityNew( "cbAuthor" ); - } ); + function run( testResults, testBox ) { + describe( + "Author Suite", + () => { + beforeEach( + ( currentSpec ) => { + model = entityNew( "cbAuthor" ); + } + ); - it( "can load properly", function(){ - var testUser = entityLoad( "cbAuthor" )[ 1 ]; - expect( testUser.isLoaded() ).toBeTrue(); - } ); + it( + "can load properly", + () => { + var testUser = entityLoad( "cbAuthor" )[ 1 ]; + expect( testUser.isLoaded() ).toBeTrue(); + } + ); - it( "can display created dates", function(){ - var d = model.getDisplayCreatedDate( timeFormat: "hh:mm tt" ); - expect( dateDiff( "d", now(), d ) ).toBe( 0 ); - } ); + it( + "can display created dates", + () => { + var d = model.getDisplayCreatedDate( timeFormat = "hh:mm tt" ); + expect( dateDiff( + "d", + now(), + d + ) ).toBe( 0 ); + } + ); - it( "can display last login timestamps", function(){ - var d = model.getDisplayLastLogin(); - expect( d ).toBe( "Never Logged In" ); + it( + "can display last login timestamps", + () => { + var d = model.getDisplayLastLogin(); + expect( d ).toBe( "Never Logged In" ); - var testUser = entityLoad( "cbAuthor" )[ 1 ]; - var d = testUser.getDisplayLastLogin( timeFormat: "hh:mm tt" ); - expect( d ).toBeDate(); - } ); + var testUser = entityLoad( "cbAuthor" )[ 1 ]; + var d = testUser.getDisplayLastLogin( timeFormat = "hh:mm tt" ); + expect( d ).toBeDate(); + } + ); - it( "can get/set all preferences", function(){ - expect( model.getAllPreferences() ).toBeStruct(); - var pref = { editor : "textarea", test : "nada" }; - model.setPreferences( pref ); + it( + "can get/set all preferences", + () => { + expect( model.getAllPreferences() ).toBeStruct(); + var pref = { editor: "textarea", test: "nada" }; + model.setPreferences( pref ); - expect( model.getPreferences() ).toBeJSON(); - expect( model.getAllPreferences() ).toBe( pref ); - } ); + expect( model.getPreferences() ).toBeJSON(); + expect( model.getAllPreferences() ).toBe( pref ); + } + ); - it( "can get and set preferences with marshalling", function(){ - // with default - var v = model.getPreference( "invalid", "test" ); - expect( v ).toBe( "test" ); + it( + "can get and set preferences with marshalling", + () => { + // with default + var v = model.getPreference( "invalid", "test" ); + expect( v ).toBe( "test" ); - // existent - var pref = { editor : "textarea", test : "nada" }; - model.setPreferences( pref ); - expect( model.getPreference( "editor" ) ).toBe( "textarea" ); + // existent + var pref = { editor: "textarea", test: "nada" }; + model.setPreferences( pref ); + expect( model.getPreference( "editor" ) ).toBe( "textarea" ); - // invalid - expect( function(){ - model.getPreference( "invalid" ); - } ).toThrow(); + // invalid + expect( + () => { + model.getPreference( "invalid" ); + } + ).toThrow(); - // with default - model.setPreference( "UnitTest", "Hello" ); - expect( model.getPreference( "UnitTest" ) ).toBe( "Hello" ); - } ); + // with default + model.setPreference( "UnitTest", "Hello" ); + expect( model.getPreference( "UnitTest" ) ).toBe( "Hello" ); + } + ); - it( "can check permissions even without a role", function(){ - expect( model.hasPermission( "test" ) ).toBeFalse(); - } ); - } ); + it( + "can check permissions even without a role", + () => { + expect( model.hasPermission( "test" ) ).toBeFalse(); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/security/SecurityRuleServiceTest.cfc b/tests/specs/contentbox-web/contentbox/unit/security/SecurityRuleServiceTest.cfc index 3f14fb354c..2f271856f9 100755 --- a/tests/specs/contentbox-web/contentbox/unit/security/SecurityRuleServiceTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/security/SecurityRuleServiceTest.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -6,30 +6,45 @@ */ component extends="tests.resources.BaseTest" { - function run( testResults, testBox ){ - describe( "Security Rule Services", function(){ - beforeEach( function( currentSpec ){ - model = prepareMock( getInstance( "SecurityRuleService@contentbox" ) ); - } ); + function run( testResults, testBox ) { + describe( + "Security Rule Services", + () => { + beforeEach( + ( currentSpec ) => { + model = prepareMock( getInstance( "SecurityRuleService@contentbox" ) ); + } + ); - it( "can get max orders", function(){ - var t = model.getMaxOrder(); - expect( t ).toBeNumeric(); - expect( t + 1 ).toBe( model.getNextMaxOrder() ); - } ); + it( + "can get max orders", + () => { + var t = model.getMaxOrder(); + expect( t ).toBeNumeric(); + expect( t + 1 ).toBe( model.getNextMaxOrder() ); + } + ); - it( "can save rules", function(){ - var t = prepareMock( entityNew( "cbSecurityRule" ) ); - model.$( "save" ).$( "getNextMaxOrder", 99 ); - model.saveRule( t ); - expect( t.getOrder() ).toBe( 99 ); + it( + "can save rules", + () => { + var t = prepareMock( entityNew( "cbSecurityRule" ) ); + model.$( "save" ).$( "getNextMaxOrder", 99 ); + model.saveRule( t ); + expect( t.getOrder() ).toBe( 99 ); - t.$property( "ruleID", "variables", 40 ); - t.setOrder( 40 ); - model.saveRule( t ); - expect( t.getOrder() ).toBe( 40 ); - } ); - } ); + t.$property( + "ruleID", + "variables", + 40 + ); + t.setOrder( 40 ); + model.saveRule( t ); + expect( t.getOrder() ).toBe( 40 ); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/security/SecurityRuleTest.cfc b/tests/specs/contentbox-web/contentbox/unit/security/SecurityRuleTest.cfc index 1e25551b9c..40a91aaf6a 100644 --- a/tests/specs/contentbox-web/contentbox/unit/security/SecurityRuleTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/security/SecurityRuleTest.cfc @@ -6,16 +6,24 @@ */ component extends="tests.resources.BaseTest" { - function run( testResults, testBox ){ - describe( "Security Rule Services", function(){ - beforeEach( function( currentSpec ){ - model = new contentbox.models.security.SecurityRule(); - } ); + function run( testResults, testBox ) { + describe( + "Security Rule Services", + () => { + beforeEach( + ( currentSpec ) => { + model = new contentbox.models.security.SecurityRule(); + } + ); - it( "be created", function(){ - expect( model ).toBeComponent(); - } ); - } ); + it( + "be created", + () => { + expect( model ).toBeComponent(); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/security/twofactor/BaseTwoFactorProviderTest.cfc b/tests/specs/contentbox-web/contentbox/unit/security/twofactor/BaseTwoFactorProviderTest.cfc index e7433f8a76..49c74f5f94 100644 --- a/tests/specs/contentbox-web/contentbox/unit/security/twofactor/BaseTwoFactorProviderTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/security/twofactor/BaseTwoFactorProviderTest.cfc @@ -9,24 +9,30 @@ component extends="tests.resources.BaseTest" { /*********************************** LIFE CYCLE Methods ***********************************/ // executes before all suites+specs in the run() method - function beforeAll(){ + function beforeAll() { super.beforeAll(); provider = getInstance( "BaseTwoFactorProvider@contentbox" ); } // executes after all suites+specs in the run() method - function afterAll(){ + function afterAll() { super.afterAll(); } /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ - describe( "Base Two Factor Provider", function(){ - it( "can get all settings", function(){ - expect( provider.getAllSettings() ).toBeStruct(); - } ); - } ); + function run( testResults, testBox ) { + describe( + "Base Two Factor Provider", + () => { + it( + "can get all settings", + () => { + expect( provider.getAllSettings() ).toBeStruct(); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/security/twofactor/TwoFactorServiceTest.cfc b/tests/specs/contentbox-web/contentbox/unit/security/twofactor/TwoFactorServiceTest.cfc index 1b7f9721cf..bea120a287 100644 --- a/tests/specs/contentbox-web/contentbox/unit/security/twofactor/TwoFactorServiceTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/security/twofactor/TwoFactorServiceTest.cfc @@ -9,123 +9,192 @@ component extends="tests.resources.BaseTest" { /*********************************** LIFE CYCLE Methods ***********************************/ // executes before all suites+specs in the run() method - function beforeAll(){ + function beforeAll() { super.beforeAll(); } // executes after all suites+specs in the run() method - function afterAll(){ + function afterAll() { super.afterAll(); structDelete( cookie, "CONTENTBOX_2FACTOR_DEVICE" ); } /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ - describe( "Two Factor Services", function(){ - beforeEach( function( currentSpec ){ - model = prepareMock( getInstance( "TwoFactorService@contentbox" ) ); - mockProvider = createStub( implements = "contentbox.models.security.twofactor.ITwoFactorProvider" ) - .$( "getName", "email" ) - .$( "getDisplayName", "email" ) - .$( "allowTrustedDevice", true ); - // Register a mock provider for testing usages - model.registerProvider( mockProvider ); - } ); - - it( "can validate global force authentication", function(){ - expect( model.isForceTwoFactorAuth() ).toBeBoolean(); - } ); - - it( "can initialize and register the default provider", function(){ - expect( model.getProviders() ).notToBeEmpty(); - } ); - - it( "can get the default provider name", function(){ - expect( model.getDefaultProvider() ).toBe( "Email" ); - } ); - - it( "can get registered providers", function(){ - var a = model.getRegisteredProviders(); - expect( a ).toInclude( "Email" ); - } ); - - it( "can get the registered providers display map", function(){ - var map = model.getRegisteredProvidersMap(); - expect( map[ 1 ].displayName ).toBe( "Email" ); - } ); - - it( "can get a provider instance", function(){ - var provider = model.getProvider( "email" ); - expect( isObject( provider ) ).toBeTrue(); - } ); - - it( "can verify providers", function(){ - expect( model.hasProvider( "email" ) ).toBeTrue(); - } ); - - it( "can unregister providers", function(){ - var provider = createStub( implements = "contentbox.models.security.twofactor.ITwoFactorProvider" ) - .$( "getName", "mock" ) - .$( "getDisplayName", "mock" ); - - model.registerProvider( provider ); - model.unRegisterProvider( "mock" ); - expect( model.hasProvider( "mock" ) ).toBeFalse(); - } ); - - xit( "can set trusted devices", function(){ - model.setTrustedDevice( "luis" ); - expect( cookie[ "CONTENTBOX_2FACTOR_DEVICE" ] ).notToBeEmpty(); - } ); - - it( "can validate trusted devices", function(){ - model.setTrustedDevice( "luis" ); - expect( model.isTrustedDevice( "luis" ) ).toBeTrue(); - - expect( model.isTrustedDevice( "mockTesting" ) ).toBeFalse(); - } ); - - it( "can send provider challenges", function(){ - var thisUser = getInstance( "AuthorService@contentbox" ).findByUsername( "lmajano" ); - var results = { error : false, messages : "message sent" }; - mockProvider.$( "sendChallenge", results ); - expect( model.sendChallenge( thisUser ) ).toBe( results ); - } ); - - story( "I can challenge for two factor authentication with trusted device features", function(){ - beforeEach( function(){ - thisUser = getInstance( "AuthorService@contentbox" ).findByUsername( "lmajano" ); - model.registerProvider( mockProvider ); - } ); - given( "A global force and no trusted device", function(){ - then( "I should challenge", function(){ - model.$( "isForceTwoFactorAuth", true ).$( "isTrustedDevice", false ); - expect( model.canChallenge( thisUser ) ).toBeTrue(); - } ); - } ); - given( "A global force and a trusted device", function(){ - then( "I should NOT challenge", function(){ - model.$( "isForceTwoFactorAuth", true ).$( "isTrustedDevice", true ); - expect( model.canChallenge( thisUser ) ).toBeFalse(); - } ); - } ); - given( "No global force but user set authentication and no trusted device", function(){ - then( "I should challenge", function(){ - thisUser.setIs2FactorAuth( true ); - model.$( "isForceTwoFactorAuth", false ).$( "isTrustedDevice", false ); - expect( model.canChallenge( thisUser ) ).toBeTrue(); - } ); - } ); - given( "No global force but user set authentication and a trusted device", function(){ - then( "I should NOT challenge", function(){ - thisUser.setIs2FactorAuth( true ); - model.$( "isForceTwoFactorAuth", false ).$( "isTrustedDevice", true ); - expect( model.canChallenge( thisUser ) ).toBeFalse(); - } ); - } ); - } ); - } ); + function run( testResults, testBox ) { + describe( + "Two Factor Services", + () => { + beforeEach( + ( currentSpec ) => { + model = prepareMock( getInstance( "TwoFactorService@contentbox" ) ); + mockProvider = createStub( + implements = "contentbox.models.security.twofactor.ITwoFactorProvider" + ) + .$( "getName", "email" ) + .$( "getDisplayName", "email" ) + .$( "allowTrustedDevice", true ); + // Register a mock provider for testing usages + model.registerProvider( mockProvider ); + } + ); + + it( + "can validate global force authentication", + () => { + expect( model.isForceTwoFactorAuth() ).toBeBoolean(); + } + ); + + it( + "can initialize and register the default provider", + () => { + expect( model.getProviders() ).notToBeEmpty(); + } + ); + + it( + "can get the default provider name", + () => { + expect( model.getDefaultProvider() ).toBe( "Email" ); + } + ); + + it( + "can get registered providers", + () => { + var a = model.getRegisteredProviders(); + expect( a ).toInclude( "Email" ); + } + ); + + it( + "can get the registered providers display map", + () => { + var map = model.getRegisteredProvidersMap(); + expect( map[ 1 ].displayName ).toBe( "Email" ); + } + ); + + it( + "can get a provider instance", + () => { + var provider = model.getProvider( "email" ); + expect( isObject( provider ) ).toBeTrue(); + } + ); + + it( + "can verify providers", + () => { + expect( model.hasProvider( "email" ) ).toBeTrue(); + } + ); + + it( + "can unregister providers", + () => { + var provider = createStub( + implements = "contentbox.models.security.twofactor.ITwoFactorProvider" + ).$( "getName", "mock" ).$( "getDisplayName", "mock" ); + + model.registerProvider( provider ); + model.unRegisterProvider( "mock" ); + expect( model.hasProvider( "mock" ) ).toBeFalse(); + } + ); + + xit( + "can set trusted devices", + () => { + model.setTrustedDevice( "luis" ); + expect( cookie[ "CONTENTBOX_2FACTOR_DEVICE" ] ).notToBeEmpty(); + } + ); + + it( + "can validate trusted devices", + () => { + model.setTrustedDevice( "luis" ); + expect( model.isTrustedDevice( "luis" ) ).toBeTrue(); + + expect( model.isTrustedDevice( "mockTesting" ) ).toBeFalse(); + } + ); + + it( + "can send provider challenges", + () => { + var thisUser = getInstance( "AuthorService@contentbox" ).findByUsername( "lmajano" ); + var results = { error: false, messages: "message sent" }; + mockProvider.$( "sendChallenge", results ); + expect( model.sendChallenge( thisUser ) ).toBe( results ); + } + ); + + story( + "I can challenge for two factor authentication with trusted device features", + () => { + beforeEach( + () => { + thisUser = getInstance( "AuthorService@contentbox" ).findByUsername( "lmajano" ); + model.registerProvider( mockProvider ); + } + ); + given( + "A global force and no trusted device", + () => { + then( + "I should challenge", + () => { + model.$( "isForceTwoFactorAuth", true ).$( "isTrustedDevice", false ); + expect( model.canChallenge( thisUser ) ).toBeTrue(); + } + ); + } + ); + given( + "A global force and a trusted device", + () => { + then( + "I should NOT challenge", + () => { + model.$( "isForceTwoFactorAuth", true ).$( "isTrustedDevice", true ); + expect( model.canChallenge( thisUser ) ).toBeFalse(); + } + ); + } + ); + given( + "No global force but user set authentication and no trusted device", + () => { + then( + "I should challenge", + () => { + thisUser.setIs2FactorAuth( true ); + model.$( "isForceTwoFactorAuth", false ).$( "isTrustedDevice", false ); + expect( model.canChallenge( thisUser ) ).toBeTrue(); + } + ); + } + ); + given( + "No global force but user set authentication and a trusted device", + () => { + then( + "I should NOT challenge", + () => { + thisUser.setIs2FactorAuth( true ); + model.$( "isForceTwoFactorAuth", false ).$( "isTrustedDevice", true ); + expect( model.canChallenge( thisUser ) ).toBeFalse(); + } + ); + } + ); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/system/CBHelperTest.cfc b/tests/specs/contentbox-web/contentbox/unit/system/CBHelperTest.cfc index c9823b3df6..d217240d1a 100644 --- a/tests/specs/contentbox-web/contentbox/unit/system/CBHelperTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/system/CBHelperTest.cfc @@ -8,51 +8,86 @@ component extends="tests.resources.BaseTest" { /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ - describe( "CB Helper", function(){ - beforeEach( function( currentSpec ){ - setup(); - cbHelper = getInstance( "CBHelper@contentbox" ); - } ); - - it( "can be created", function(){ - expect( cbHelper ).toBeComponent(); - } ); - - describe( "Site related methods", function(){ - it( "can build the site root", function(){ - expect( cbHelper.siteRoot() ).toInclude( "http://127.0.0.1" ); - } ); - - it( "can build the site base url", function(){ - expect( cbHelper.siteBaseUrl() ).toInclude( "http://127.0.0.1" ).notToInclude( "index.cfm" ); - } ); - - it( "can build the site name", function(){ - expect( cbHelper.siteName() ).toInclude( "Default Site" ); - } ); - - it( "can build the site tag line", function(){ - expect( cbHelper.siteTagLine() ).notToBeEmpty(); - } ); - - it( "can build the site description", function(){ - expect( cbHelper.siteDescription() ).notToBeEmpty(); - } ); - - it( "can build the site keywords", function(){ - cbHelper.siteKeywords(); - } ); - - it( "can build the site email", function(){ - expect( cbHelper.siteEmail() ).notToBeEmpty(); - } ); - - it( "can build the site outgoing email", function(){ - expect( cbHelper.siteOutgoingEmail() ).notToBeEmpty(); - } ); - } ); - } ); + function run( testResults, testBox ) { + describe( + "CB Helper", + () => { + beforeEach( + ( currentSpec ) => { + setup(); + cbHelper = getInstance( "CBHelper@contentbox" ); + } + ); + + it( + "can be created", + () => { + expect( cbHelper ).toBeComponent(); + } + ); + + describe( + "Site related methods", + () => { + it( + "can build the site root", + () => { + expect( cbHelper.siteRoot() ).toInclude( "http://127.0.0.1" ); + } + ); + + it( + "can build the site base url", + () => { + expect( cbHelper.siteBaseUrl() ).toInclude( "http://127.0.0.1" ).notToInclude( "index.cfm" ); + } + ); + + it( + "can build the site name", + () => { + expect( cbHelper.siteName() ).toInclude( "Default Site" ); + } + ); + + it( + "can build the site tag line", + () => { + expect( cbHelper.siteTagLine() ).notToBeEmpty(); + } + ); + + it( + "can build the site description", + () => { + expect( cbHelper.siteDescription() ).notToBeEmpty(); + } + ); + + it( + "can build the site keywords", + () => { + cbHelper.siteKeywords(); + } + ); + + it( + "can build the site email", + () => { + expect( cbHelper.siteEmail() ).notToBeEmpty(); + } + ); + + it( + "can build the site outgoing email", + () => { + expect( cbHelper.siteOutgoingEmail() ).notToBeEmpty(); + } + ); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/system/SettingServiceTest.cfc b/tests/specs/contentbox-web/contentbox/unit/system/SettingServiceTest.cfc index 1a63acf65e..47a6083630 100755 --- a/tests/specs/contentbox-web/contentbox/unit/system/SettingServiceTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/system/SettingServiceTest.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -8,25 +8,36 @@ component extends="tests.resources.BaseTest" { /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ - describe( "Settings Services", function(){ - beforeEach( function( currentSpec ){ - model = prepareMock( getInstance( "SettingService@contentbox" ) ); - cache = model.getSettingsCacheProvider(); - } ); + function run( testResults, testBox ) { + describe( + "Settings Services", + () => { + beforeEach( + ( currentSpec ) => { + model = prepareMock( getInstance( "SettingService@contentbox" ) ); + cache = model.getSettingsCacheProvider(); + } + ); - it( "can flush settings", function(){ - model.storeSettings( { global : {}, sites : {} } ); - expect( model.getAllSettings() ).toBeEmpty(); - model.flushSettingsCache(); - expect( model.getAllSettings() ).notToBeEmpty(); - } ); + it( + "can flush settings", + () => { + model.storeSettings( { global: {}, sites: {} } ); + expect( model.getAllSettings() ).toBeEmpty(); + model.flushSettingsCache(); + expect( model.getAllSettings() ).notToBeEmpty(); + } + ); - it( "can get all settings", function(){ - var r = model.getAllSettings(); - expect( r ).toBeStruct().notToBeEmpty(); - } ); - } ); + it( + "can get all settings", + () => { + var r = model.getAllSettings(); + expect( r ).toBeStruct().notToBeEmpty(); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/system/SiteTest.cfc b/tests/specs/contentbox-web/contentbox/unit/system/SiteTest.cfc index 0322b60700..3d912f8d2b 100755 --- a/tests/specs/contentbox-web/contentbox/unit/system/SiteTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/system/SiteTest.cfc @@ -1,4 +1,4 @@ -/** +/** * ContentBox - A Modular Content Platform * Copyright since 2012 by Ortus Solutions, Corp * www.ortussolutions.com/products/contentbox @@ -8,25 +8,39 @@ component extends="tests.resources.BaseTest" { /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ - describe( "Site", function(){ - beforeEach( function( currentSpec ){ - model = prepareMock( getInstance( "siteService@contentbox" ).new() ); - } ); + function run( testResults, testBox ) { + describe( + "Site", + () => { + beforeEach( + ( currentSpec ) => { + model = prepareMock( getInstance( "siteService@contentbox" ).new() ); + } + ); - it( "can be created", function(){ - expect( model ).toBeComponent(); - } ); + it( + "can be created", + () => { + expect( model ).toBeComponent(); + } + ); - it( "can have an empty domain aliases by default", function(){ - expect( model.getDomainAliases() ).toBeArray().toBeEmpty(); - } ); + it( + "can have an empty domain aliases by default", + () => { + expect( model.getDomainAliases() ).toBeArray().toBeEmpty(); + } + ); - it( "can store domain aliases as a json string", function(){ - model.setDomainAliases( [ "www\.foo\.com", "bar\.com" ] ); - expect( model.getDomainAliases() ).toBeArray().toHaveLength( 2 ); - } ); - } ); + it( + "can store domain aliases as a json string", + () => { + model.setDomainAliases( [ "www\.foo\.com", "bar\.com"] ); + expect( model.getDomainAliases() ).toBeArray().toHaveLength( 2 ); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/ui/AdminMenuServiceTest.cfc b/tests/specs/contentbox-web/contentbox/unit/ui/AdminMenuServiceTest.cfc index 0315139536..3ab982cc83 100755 --- a/tests/specs/contentbox-web/contentbox/unit/ui/AdminMenuServiceTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/ui/AdminMenuServiceTest.cfc @@ -8,35 +8,55 @@ component extends="tests.resources.BaseTest" { /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ - describe( "Admin Menu Services", function(){ - beforeEach( function( currentSpec ){ - model = prepareMock( getInstance( "AdminMenuService@contentbox" ) ); - prc = getRequestContext().getPrivateCollection(); - prc.oCurrentAuthor = prepareMock( entityNew( "cbAuthor" ) ).$( "hasPermission", true ); - } ); - - it( "can generate the menu", function(){ - var r = model.generateMenu(); - expect( r ).notToBeEmpty(); - } ); - - it( "should ignore the removal of non-existent top menu items without throwing exceptions ", function(){ - model.removeTopMenu( "invalid" ); - } ); - - it( "should ignore the removal of non-existent header menu items without throwing exceptions ", function(){ - model.removeHeaderMenu( "invalid" ); - } ); - - it( "should ignore the removal of non-existent header sub menu items without throwing exceptions ", function(){ - model.removeHeaderSubMenu( "invalid", "bogus" ); - } ); - - it( "should ignore the removal of non-existent sub menu items without throwing exceptions ", function(){ - model.removeSubMenu( "invalid", "bogus" ); - } ); - } ); + function run( testResults, testBox ) { + describe( + "Admin Menu Services", + () => { + beforeEach( + ( currentSpec ) => { + model = prepareMock( getInstance( "AdminMenuService@contentbox" ) ); + prc = getRequestContext().getPrivateCollection(); + prc.oCurrentAuthor = prepareMock( entityNew( "cbAuthor" ) ).$( "hasPermission", true ); + } + ); + + it( + "can generate the menu", + () => { + var r = model.generateMenu(); + expect( r ).notToBeEmpty(); + } + ); + + it( + "should ignore the removal of non-existent top menu items without throwing exceptions ", + () => { + model.removeTopMenu( "invalid" ); + } + ); + + it( + "should ignore the removal of non-existent header menu items without throwing exceptions ", + () => { + model.removeHeaderMenu( "invalid" ); + } + ); + + it( + "should ignore the removal of non-existent header sub menu items without throwing exceptions ", + () => { + model.removeHeaderSubMenu( "invalid", "bogus" ); + } + ); + + it( + "should ignore the removal of non-existent sub menu items without throwing exceptions ", + () => { + model.removeSubMenu( "invalid", "bogus" ); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/ui/ThemeServiceTest.cfc b/tests/specs/contentbox-web/contentbox/unit/ui/ThemeServiceTest.cfc index 393b3ac7bd..cce932f680 100755 --- a/tests/specs/contentbox-web/contentbox/unit/ui/ThemeServiceTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/ui/ThemeServiceTest.cfc @@ -8,51 +8,68 @@ component extends="tests.resources.BaseTest" { /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ - describe( "Theme Services", function(){ - beforeEach( function( currentSpec ){ - setup(); - cbHelper = getInstance( "CBHelper@contentbox" ); - model = getInstance( "ThemeService@contentbox" ); - } ); - - it( "can build the theme registry", function(){ - expect( model.getThemeRegistry() ).notToBeEmpty(); - expect( model.getCoreThemesPath() ).notToBeEmpty(); - expect( model.getCustomThemesPath() ).notToBeEmpty(); - expect( model.getCBHelper() ).toBeComponent(); - } ); - - xit( "can find maintenance view", function(){ - var prc = getRequestContext().getPrivateCollection(); - prc.cbThemeRoot = "/"; - expect( model.themeMaintenanceViewExists() ).toBeFalse(); - - // No - prc.cbThemeRoot = "/modules/contentbox/themes/default"; - expect( model.themeMaintenanceViewExists() ).toBeTrue(); - } ); - - xit( "can find the maintenance layout", function(){ - var prc = getRequestContext().getPrivateCollection(); - prc.cbThemeRoot = "/"; - expect( model.getThemeMaintenanceLayout() ).toBe( "pages" ); - - // No - prc.cbThemeRoot = "/modules/contentbox/themes/default"; - expect( model.getThemeMaintenanceLayout() ).toBe( "maintenance" ); - } ); - - xit( "can find the search layout", function(){ - var prc = getRequestContext().getPrivateCollection(); - prc.cbThemeRoot = "/"; - expect( model.getThemeSearchLayout() ).toBe( "pages" ); - - // No - prc.cbThemeRoot = "/modules/contentbox/themes/default"; - expect( model.getThemeSearchLayout() ).toBe( "search" ); - } ); - } ); + function run( testResults, testBox ) { + describe( + "Theme Services", + () => { + beforeEach( + ( currentSpec ) => { + setup(); + cbHelper = getInstance( "CBHelper@contentbox" ); + model = getInstance( "ThemeService@contentbox" ); + } + ); + + it( + "can build the theme registry", + () => { + expect( model.getThemeRegistry() ).notToBeEmpty(); + expect( model.getCoreThemesPath() ).notToBeEmpty(); + expect( model.getCustomThemesPath() ).notToBeEmpty(); + expect( model.getCBHelper() ).toBeComponent(); + } + ); + + xit( + "can find maintenance view", + () => { + var prc = getRequestContext().getPrivateCollection(); + prc.cbThemeRoot = "/"; + expect( model.themeMaintenanceViewExists() ).toBeFalse(); + + // No + prc.cbThemeRoot = "/modules/contentbox/themes/default"; + expect( model.themeMaintenanceViewExists() ).toBeTrue(); + } + ); + + xit( + "can find the maintenance layout", + () => { + var prc = getRequestContext().getPrivateCollection(); + prc.cbThemeRoot = "/"; + expect( model.getThemeMaintenanceLayout() ).toBe( "pages" ); + + // No + prc.cbThemeRoot = "/modules/contentbox/themes/default"; + expect( model.getThemeMaintenanceLayout() ).toBe( "maintenance" ); + } + ); + + xit( + "can find the search layout", + () => { + var prc = getRequestContext().getPrivateCollection(); + prc.cbThemeRoot = "/"; + expect( model.getThemeSearchLayout() ).toBe( "pages" ); + + // No + prc.cbThemeRoot = "/modules/contentbox/themes/default"; + expect( model.getThemeSearchLayout() ).toBe( "search" ); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/ui/editors/CKEditorTest.cfc b/tests/specs/contentbox-web/contentbox/unit/ui/editors/CKEditorTest.cfc index 73c35b0421..4df26afbfe 100755 --- a/tests/specs/contentbox-web/contentbox/unit/ui/editors/CKEditorTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/ui/editors/CKEditorTest.cfc @@ -8,34 +8,42 @@ component extends="tests.resources.BaseTest" { /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ - describe( "CKEditor", function(){ - beforeEach( function( currentSpec ){ - model = prepareMock( getInstance( "CKEditor@contentbox-ckeditor" ) ); - prc = getRequestContext().getPrivateCollection(); - prc.cbAdminEntryPoint = "/cbadmin"; - } ); - - it( "can compileJS", function(){ - makePublic( model, "compileJS" ); - var t = model.compileJS( - { - toolbar : { "unit" : "true" }, - excerptToolbar : { "excerptTest" : "true" } - }, - { extraPlugins : listToArray( model.getExtraPlugins() ) }, - { extraConfig : "extraconfig = 'true'" }, - { contentsCss : [ "/unit/css" ] } + function run( testResults, testBox ) { + describe( + "CKEditor", + () => { + beforeEach( + ( currentSpec ) => { + model = prepareMock( getInstance( "CKEditor@contentbox-ckeditor" ) ); + prc = getRequestContext().getPrivateCollection(); + prc.cbAdminEntryPoint = "/cbadmin"; + } ); - expect( t ).notToBeEmpty(); - expect( t ) - .toInclude( "extraconfig" ) - .toInclude( "unit/css" ) - .toInclude( """unit"":" ) - .toInclude( """excerptTest"":" ); - } ); - } ); + it( + "can compileJS", + () => { + makePublic( model, "compileJS" ); + var t = model.compileJS( + { + toolbar : { "unit": "true" }, + excerptToolbar: { "excerptTest": "true" } + }, + { extraPlugins: listToArray( model.getExtraPlugins() ) }, + { extraConfig: "extraconfig = 'true'" }, + { contentsCss: [ "/unit/css"] } + ); + + expect( t ).notToBeEmpty(); + expect( t ) + .toInclude( "extraconfig" ) + .toInclude( "unit/css" ) + .toInclude( """unit"":" ) + .toInclude( """excerptTest"":" ); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/ui/editors/EditorServiceTest.cfc b/tests/specs/contentbox-web/contentbox/unit/ui/editors/EditorServiceTest.cfc index 36926648a0..8bf7b29b8f 100755 --- a/tests/specs/contentbox-web/contentbox/unit/ui/editors/EditorServiceTest.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/ui/editors/EditorServiceTest.cfc @@ -8,36 +8,50 @@ component extends="tests.resources.BaseTest" { /*********************************** BDD SUITES ***********************************/ - function run( testResults, testBox ){ - describe( "Editor Services", function(){ - beforeEach( function( currentSpec ){ - model = getInstance( "EditorService@contentbox" ); - } ); + function run( testResults, testBox ) { + describe( + "Editor Services", + () => { + beforeEach( + ( currentSpec ) => { + model = getInstance( "EditorService@contentbox" ); + } + ); - it( "can get registered editors", function(){ - model.getEditors()[ "test" ] = this; - model.getEditors()[ "Awesome" ] = this; - var a = model.getRegisteredEditors(); + it( + "can get registered editors", + () => { + model.getEditors()[ "test" ] = this; + model.getEditors()[ "Awesome" ] = this; + var a = model.getRegisteredEditors(); - expect( a ) - .toInclude( "Awesome" ) - .toInclude( "ckeditor" ) - .toInclude( "test" ); - debug( a ); - } ); + expect( a ) + .toInclude( "Awesome" ) + .toInclude( "ckeditor" ) + .toInclude( "test" ); + debug( a ); + } + ); - it( "can register a new editor", function(){ - var editor = prepareMock( new MockEditor() ); - model.registerEditor( editor ); - assertEquals( editor, model.getEditor( "mock-editor" ) ); - } ); + it( + "can register a new editor", + () => { + var editor = prepareMock( new MockEditor() ); + model.registerEditor( editor ); + assertEquals( editor, model.getEditor( "mock-editor" ) ); + } + ); - it( "can unregister editors", function(){ - var editor = prepareMock( new MockEditor() ); - model.registerEditor( editor ).unRegisterEditor( "mock-editor" ); - assertFalse( structKeyExists( model.getEditors(), "mock-editor" ) ); - } ); - } ); + it( + "can unregister editors", + () => { + var editor = prepareMock( new MockEditor() ); + model.registerEditor( editor ).unRegisterEditor( "mock-editor" ); + assertFalse( structKeyExists( model.getEditors(), "mock-editor" ) ); + } + ); + } + ); } -} +} \ No newline at end of file diff --git a/tests/specs/contentbox-web/contentbox/unit/ui/editors/MockEditor.cfc b/tests/specs/contentbox-web/contentbox/unit/ui/editors/MockEditor.cfc index 726f64734b..eddfd5eb87 100644 --- a/tests/specs/contentbox-web/contentbox/unit/ui/editors/MockEditor.cfc +++ b/tests/specs/contentbox-web/contentbox/unit/ui/editors/MockEditor.cfc @@ -1,23 +1,27 @@ component implements="contentbox.models.ui.editors.IEditor" { - function init(){ + function init() { return this; } - function getName(){ + function getName() { return "mock-editor"; } - function getDisplayName(){ + + function getDisplayName() { return "Mock Editor"; } - function startup(){ + function startup() { + } - function shutdown(){ + function shutdown() { + } - function loadAssets(){ + function loadAssets() { + } -} +} \ No newline at end of file