From b08b3a2019a58d6c94f51bdf795abb2aec144f08 Mon Sep 17 00:00:00 2001 From: Rijk van Zanten Date: Tue, 3 Dec 2019 19:31:13 -0500 Subject: [PATCH 01/11] v8.0.0 (#1516) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Issue Fix #1180 (#1183) * Issue fix #1191 (#1192) * Issue fix #1196 (#1197) * Add 2fa authentication (#1031) * Parent + Nested validation changes (#1138) * Add migration schema for 2FA Secret user field * Add 2fa_secret field to FieldsSeeder * Create Missing 2FA Password Exception * Add googleauthenticator dependency * Add getter for User's 2FA secret * Check for otp param in login request, and login with it * Add enforce_2fa parameter to directus_settings * Create Utils endpoint and service method to generate 2fa secret * Add enforce_2fa field to roles * Add enforce_2fa field to FieldsSeeder * Change Missing2FAPasswordException error code to 111 * Change 2FA Library * Change 2fa_secret interface in FieldsSeeder * Created exception for invalid otp * Changed findUserWithCredentials to through an InvalidOTPException on otp check * Created new exception if 2fa is enforced but not enabled by user * Added function to check if 2fa is enforced for a user * Check in AuthenticationMiddleware whether 2fa is enforced and enabled for user * Add optional needs2FA field to auth token and on token refresh * Catch error if enforce_2fa column doesn't exist Fixes crash when has2FAEnforced is called on a DB that hasn't been migrated * Use relative positions for target path array to check user edit * Fix unset on payload_arr instead of payload * Change 2FA activation on login to use activate2FA endpoint * Update ItemsService.php * Issue Fix #1194 (#1195) * Issue Fix #1194 * Update comment * Valildation issue of O2M/M2O at insertion (#1198) * Fox #1201 (#1202) * Fix #1203 (#1204) * Update collections() method in types.php (#1184) There are cases when $type is not a string but an object that inherits from ObjectType. In that situation array_key_exists failing because it should get only integers or strings as a first parameter. So in order to avoid that the 'name' property of the object is used as a key. * Improve YouTube Embed Provider (#1210) Adds in detection and parsing for youtu.be shorthand URLs. * Add check for environment on bootstrap (#1215) * Fix #1186 [Create new error code for invalid login entity] (#1218) * Fix #1217 (Changing password over the CLI doesn't work) (#1220) * Feature/audio video upload (#1214) * added file meta data for audio/video * updates as per PR feedback * Fix #1207 [Permission denied issue when using translation interface] (#1221) * Fix for smtp send mail issue #1205 (#1223) * Fix for smtp send mail issue #1205 Missing additional config settings https://github.com/directus/api/issues/1205 * Update Schema.php * Fix 1232[Auth token is not refreshed] (#1233) * Change Authencation Error code to 114 from 109 (#1231) * Fix issue while update item. (#1224) * #1227 : Ignore all the alias fields except file interface (#1240) * Fix #1224 [Deletion of m2o/o2m field error for enabled cache] (#1241) * Fix 845 (#1244) * Change namespace for PHPUnit. * Removing old tests. * Fix #1238 [PDF support for Embedded URL] (#1245) * Fix #1238[PDF support for Embedded URL] * Add array support * Update comment * Update Files.php * Fix #1243[Dynamic charset for DB] (#1246) * Fix #1249[saveData: height is set to width] (#1251) * Fix #2017[Renaming `Public` role gives `unauthorized` error on API calls] (#1253) * Revert "Fix #2017[Renaming `Public` role gives `unauthorized` error on API calls] (#1253)" (#1254) This reverts commit 7fe9056f401f937d4863252f0e604c2deff8c3bf. * FIX/core/Directus/Files.php: return $height instead of $width (#1250) * Fix #1255 [Add support of batch Create/Update/Delete for user] (#1257) * Fix #1255 [Support batch create/update/delete for user] * Add exception * Fix directus/app#2017 (#1256) * Fix #2017[Renaming `Public` role gives `unauthorized` error on API calls] * src * Remove unwanted file from use * Fix #729 [Can't properly query nested fields on Files field] (#1260) * #1216 : Solved issue in O2M relationship of table itself (#1259) * Fix #1209 [M2M relation with directus_collections cant be saved] (#1261) * Fix #1209[M2M relation with directus_collections cant be saved] * Implement condition on update * Define variable * Fix #1209[M2M relation with directus_collections cant be saved] * πŸ™†πŸ»β€β™‚οΈ * Fix #1266 (#1267) * Fix Warning: Cannot use a scalar value as an array in /src/core/Directus/Config/StatusMapping.php on line 103 (#1268) * Fix Notice: Undefined variable: filterFields in src/core/Directus/Database/TableGateway/RelationalTableGateway.php on line 2125 (#1270) * Fix #1237 (#1265) * Project name fix (#1272) * Adds support for environment variables in CLI (#1276) * Cleans up some unused/deprecated files in the repository (#1277) * Fix #1248 [API cannot go into deeper on user data] (#1282) * Add proper exit codes for CLI (#1281) * Fix cache.enabled not respected in cache service (#1273) This fixes an issue where cache.enabled is false but caching is still working. * Add CLI cache:clear (#1274) * Fix #1284[Broken user related fields] (#1287) * Fix #1279 [wysiwyg-full - add image - Call to a member function isOneToMany() on null] (#1288) * fixed bug with incorrect height (#1293) * Execute migrations automatically (#1296) * Remove middleware for register webhook and add it before registeration of hooks * Need to add middleware for directory dependency * Fix #1302 - Internal server error when selecting/checking a Checkbox Relational field after deleting some of the related items (#1307) * Fix #1308 - Checkbox-relational field issue when unchecking value (#1309) * Fix #1308 - Checkbox-relational field issue when unchecking value * Update RelationalTableGateway.php * Add Aliyun OSS settings to config schema (#1299) * Extend config schema to support PDO options. (#1295) * Extend config schema to support PDO options. * Make driver_options database config setting optional. * Replcae with getQueryParams method of slim (#1313) * Fix Undefined Variable - /src/core/Directus/Console/Common/Setting.php on line 24 (#1314) * Replace with getQueryParams method of slim (#1317) * Fix response data contains json object instead of array (#1318) * Fix #1310[Resolve issue with updatingNestd m2o/o2m/m2m] (#1320) * Fix #1321 [Resolve bug with system date and system user validation] (#1322) * Resolve Authentication token issue after upgrade to 2.6.0 (#1326) * Fix #1329 [Add new fields to / endpoint] (#1332) * Fix #1329 * Fix #1329 [Add new fields to / endpoint] * fix issue #1330 (#1331) * Rename color with project_color key (#1334) * Fix #1333 [Return Unauthorised when public role not have the respected permission] (#1336) * Fix #1333 [Return Unauthorized when public role not have the respected permission * Add comment * Session-based auth flow along with kill functionality (#1280) * Fix #1263[Rethink Auth Flow] * Kill User Session * Add Expiry time * Expire and cookie * Auth Flow - Modify code base * Resolve browser cache remove issue * Remove PHPSESSIONID reset code * Cookie name based on projject name, Merge authentication endpoint * Support of mode in sso * Add seeder into migrations * Remove warning of container * Add required flag for user in fields table from migrations * Add endpoint to fetch the user's session * Update user's session to loggedin user session endpoint * Allow cross origin cookie * Set credentials response header dynamically * Fix empty FK - do not continue if FK is empty, otherwise, it will not display the entry as if it was not saved. (#1342) * Fix #1343 [Update directus_files field type] (#1346) * fix parsing env variables (#1347) * Fix CORS issue for system endpoint (#1352) * Fix #1348 (#1353) * Fix wrong chache naming. (#1354) * Fix issue when deleting a file and saving the item (#1360) * Fix #1359 [Pagination not working] (#1362) * fix readme ( branch to submit PRs "master" -> "develop") (#1365) * Ignore ddev config folder * Fix unaccessible public endpoints (#1367) * Fix CORS origin * for public preflight endpoints (#1369) * add gitpod.io support (#1356) * Add requires2FA flag at / endpoint (#1370) * Set default value if the value is not set (#1373) * CORS issue for public endpoint (#1374) * Fix Warning: Illegal string offset 'field' in src/endpoints/Settings.php on line 89 when query param contains single=1 (#1375) * Fix Warning: Illegal string offset 'field' in src/endpoints/Settings.php on line 89 when query param contains single=1 * Update Settings.php * Resolve undefined class ArrayUtils error * Fetch single sign on providers * style updates (#1382) * Update withHeaders + add note * Fix #1384 [Remove entries from directus_relations on delete the collection] (#1386) * Fix #1381 [Throwing 500 response code on mail sending fail] (#1387) * Fix #1329 [Update the name of variable from settings table] (#1389) * Fix #1329 [Update the name of variable from settings table] * Update comment * Fix the general settings schema upgrade - consider the new installation as well with already existing fields (#1391) * New project flow (#1399) * Replace migrations file from config folder to migrations folder * Return the project list * Remove unwanted code * Projects endpoint * Remove unwanted code * Remove unwanted code * Remove unwanted code * Remove default _ for secretkey and newtimzone function of datetimeutil * Check requirement endpoint (#1398) * Check requirement endpoint * Add endpoint * Update ProjectService.php * Don't verify super admin with hashing * Remove warning of non static method 'createJsonFileContent' for project create * Remove _ as private flas (#1403) * Remove password_verfiy and add equals operator * Fix integrity constraint (#1400) * Update 2FA flow to work with cookies Squashed commit of the following: commit a543c44d799abe4d9b0f8560b4d5f044320bc966 Author: rijkvanzanten Date: Fri Nov 8 16:20:45 2019 -0500 Use correct response format for 2fa util commit ab06c5567a230935d0887a92eaef2910d4e77f73 Author: rijkvanzanten Date: Fri Nov 8 15:42:35 2019 -0500 Rename activate2FA to activate_2fa and allow `me` for user updates commit 7b429ab849be81686113d9b2a946e0e1b2b771fc Author: Binal Gajjar Date: Fri Nov 8 22:46:30 2019 +0530 Set NULL if data array is empty commit c5c7bf6ddfb941088530d47cbb1f618c16c58954 Author: Binal Gajjar Date: Fri Nov 8 22:37:17 2019 +0530 Remove needs2FA param from authtoken commit 5b4b21ab72545e259b390b446b60aff8168f592d Author: Binal Gajjar Date: Fri Nov 8 22:35:41 2019 +0530 Throw error if 2FA is not enabled * clearer existing install response * update error message * Fix #1380 [Set default requires2FA flag] (#1388) * Redirect the users to /admin in sso (#1407) * Redirect the users to /admin in sso * 2FA flow for SSO * Remove unwanted file from use statement * Default to UTC timezone on new project installs (when there's no config) * update sso icon colors * Update the size of token field * Update the size of token field * Update the size of static token * Resolve redirection to /admin? Resolve redirection to `/admin?` instead of `/admin` * Add missing 2fa secret column in seeds * Throw exception for SSO (#1411) * Redirect the users to /admin in sso * 2FA flow for SSO * Remove unwanted file from use statement * Throw the exception when 2FA enforced or enabled * Fix 2fa column * Fix 2fa column * Ignore the files which start with _ * Restrict private and _ project from listing (#1415) * Restrict private files from listing * Return the filename instead of projectname from scan funciton * Add a validation of boolean to private flag. * Fix #1395[/server/ping should ignore project] (#1416) * Update error code for unknown project exception * Update FieldsConfig.php (#1413) Without this fix the GrapQL query brings values only in case when the M2M field has exactly the same name as the related collection. It can be ok, but for cases when it's required to have mutliple M2M fields pointing to the same collection, (e.g. there 2 collections - games and tags, and so we need to specify Primary and Secondary tags for each game). So with current implementation we cannot create primaryTags and secondaryTag fields, we should use 'tags' field instead, but its only one, and we need 2. So this fix obtaining fieldName from parameters and using it for relation and not a collection name. * Remove unwanted files (#1421) * V8.0.0 (#1414) * Redirect to correct endpoint for app * Redirect to admin based on relative url (works in sub-folder) * Update request / reset password to be all app based * Add trailing slash to admin redirect * Add project key to reset password * Restrict private and _ project from listing (#1415) * Restrict private files from listing * Return the filename instead of projectname from scan funciton * Add a validation of boolean to private flag. * Add redirect_url param * update settings seeder to contain all default options * public role description * relations alpha order * Fix false positive in sso 2fa block * add enforce_2fa to roles * activity seeder updates icons and widths * seeder for directus files need to check β€œdescription” options array format * directus settings seeder updates * Add support for webhooks Squashed commit of the following: commit ce6ffac50fedb2bdd427a23b9284bf4cd04d35b7 Merge: 667d960c1 e0630e84f Author: rijkvanzanten Date: Tue Nov 12 11:51:19 2019 -0500 Merge branch 'develop' into webhooks commit 667d960c118fc37a6aa103f6d978f093d7f58200 Merge: be839255e 557a83b99 Author: rijkvanzanten Date: Tue Nov 12 11:17:11 2019 -0500 Merge branch 'v8.0.0' into webhooks commit be839255e0e0e5ce98fcdd28dad59418ff636da8 Merge: f51c51a57 41fd0b64f Author: rijkvanzanten Date: Tue Nov 12 11:17:07 2019 -0500 Merge branch 'develop' into webhooks commit 557a83b99608bb2ff66c37b01c9751173492a07b Author: rijkvanzanten Date: Tue Nov 12 10:54:13 2019 -0500 Fix false positive in sso 2fa block commit 0989b310c425e2c1b0a577178db2dd9505647eb5 Author: Ben Haynes Date: Tue Nov 12 10:49:54 2019 -0500 relations alpha order commit 8f15ad6e2cd477d60a4d8d97d222bd2b863f1a9a Author: Ben Haynes Date: Tue Nov 12 10:49:42 2019 -0500 public role description commit 555ba2f57f25d976ebf7c15c2f781adbd12b6839 Author: Ben Haynes Date: Tue Nov 12 10:46:22 2019 -0500 update settings seeder to contain all default options commit 9816a4a66989dd2880572d42d6c636791c25066c Author: Binal Gajjar Date: Tue Nov 12 20:41:54 2019 +0530 Add redirect_url param commit 3ba370891b77401a6c2f3a737fcaf93a741657ce Merge: 379457d0b 0629167af Author: Binal Gajjar Date: Tue Nov 12 20:30:11 2019 +0530 Merge branch 'v8.0.0' of https://github.com/directus/api into v8.0.0 commit 0629167af84fd8211c03cd79108a2c1cc02d8061 Author: rijkvanzanten Date: Mon Nov 11 18:33:17 2019 -0500 Add project key to reset password commit 2bcd474b983b6dce41a0df3357c21e57349e29a6 Author: rijkvanzanten Date: Mon Nov 11 18:33:05 2019 -0500 Add trailing slash to admin redirect commit 4a0ccf6a2af697368ad3cef9b39c2758cd5541e4 Author: rijkvanzanten Date: Mon Nov 11 16:13:34 2019 -0500 Update request / reset password to be all app based commit e42fbf96b74f23afe941ac6c30dd122153d1d045 Author: rijkvanzanten Date: Mon Nov 11 16:13:05 2019 -0500 Redirect to admin based on relative url (works in sub-folder) commit 9f24d50d66848f414213cf6b12c4cc9a8c7be527 Author: rijkvanzanten Date: Mon Nov 11 15:17:59 2019 -0500 Redirect to correct endpoint for app commit f51c51a571a25eb3e04a184a457d1b3adebefcc7 Author: Binal Gajjar Date: Fri Nov 8 22:44:15 2019 +0530 Webhook Implementation (#1304) * Webhook implementation * Webhook development * Fix 29 * Register the webhook * Webhook seed transfer into migrations * Update default seeder * Update comment * Update comment * Add Status Field * directus users seeds * remove unused seeder data * missing comma * Added missing comma * settings defaults * setup telemetry and default locale * Remove directus activity seen table (#1422) * Remove directus activity seen * Revert back the activity seen field from upgrades * webhooks seeds * webhooks update * Rename webhook draft->inactive published->active + delete deleted * update webhooks schema migrations * webhooks url placeholder * Use collections interface for collection chooser on webhooks * webhooks info * Don't enforce user.locale to be set * Bump version * hide dividers on browse * nice defaults for webhooks layout * better webhooks layout * Revert "Fix issue when deleting a file and saving the item (#1360)" (#1423) This reverts commit 37ef295f40a4117f33ba2b53818fc2832653c130. * Revert "Fix the general settings schema upgrade - consider the new installation as well with already existing fields (#1391)" (#1424) This reverts commit 483e065d00ed307f3f25d06ff1aa924633fe9fae. * Update the current migrations for remove unwanted code and update the icons (#1425) * Fix #1429 [Activity datetime is incorrect] (#1430) * add directus user theme field * Update migration files to check if column exist then pnly drop (#1436) * Add DB condition in migration to check whether column exists. * Fix Constant Imagick::ALPHACHANNEL_REMOVE is undefined (#1438) When using Imagick less than version 3.4.4, it will throw error `Constant Imagick::ALPHACHANNEL_REMOVE is undefined`. The const `ALPHACHANNEL_REMOVE` only exist in 3.4.4 as described [here](https://github.com/Imagick/imagick/issues/281). * Add Migration for theme (#1444) * Fix #1442 [Reset password throws email error on inactive user] (#1445) * Add Migration for theme * Fix #1442 [Reset password throws email error on inactive user] * Update syntax for insert * User role m2m to o2m (#1435) * Update role to m2o * Remove debug code * If exist condition * Update migrations/db/seeds/RelationsSeeder.php * Fix #1434 [Clean up /projects /server/projects setup] (#1439) * Fix #1434 * Remove unwanted code * Try catch for response * Remove the superadmin token from payload and place it as a param * Remove admin condition to delete the project * Remove whitespace * Fix #1429 [Convert current timezone to UTC timezone] (#1447) * Fix #1450 (#1451) * Issue fix 1450 * Remove optional from social_providers as it will add a blank string too. * Fix #1417 [Resolve edit permission is required to create a file] (#1452) * Fix #1417 [Resolve edit permission is required to create a file] * Remove unwanted enter from file * Remove unwanted files from git commit * Remove unwanted files from git commit * Revert " Fix #1450 (#1451)" (#1454) This reverts commit 68e1717b0faa793825353158f87860ade9cec19a. * Fix project install * Stop migrations execution for server endpoints (#1453) * Stop migrtions execution for server endpoints * Remove trailing slash from get request * Fix #1449 [Support _ for projectname] (#1455) * Support for redis cluster (#1441) * Add support for redis cluster * Add cache adapter type for rediscluster * Use cache/cache for dev-master (which support RedisCluster) Fix instanciation of RedisCluster * Bump version * Use -1 for undefined error code * Log errors to file on failed sso * Add migrations for using repeater for collection translations * Make the api endpoint /server/projects works with docker environments variables (#1470) * Make the api endpoint /server/projects works with docker environments variables DIRECTUS_USE_ENV=1 * Change default project name to _ * Fix #1450 [Installer creates format issues in config file] (#1472) * Fix #1450 [Installer creates format issues in config file] * Add comma after array * Fix #1427 (#1469) * Adding command line support for new project flow (#1464) * Fix commannd line issues * Add upgrades migrations in cmd installtion * Rename -N to -k and add it to the list of available options * Make the use if the telemetry service configurable (#1420) * Make the telemetry requests configurable * Add new config setting to the schema * Remove telemetry from configuration file * Remove telemetry from configuration file * Remove telemetry from schema * Remove extra comma * Fetch the telemetry from settings table instead of configuration file * Fixed primary key fields Graphql definition (#1418) * Fixed primary key fields Graphql definition The check for primary key fields was wrong so they never are defined as ID. So the Int! definition raises a Graphql validation error on primary key fields: Interface field Node.id expects type ID but ###.id is type Int!. * Code style improvements Used "if" instead ternary operator and removed unnecessary "== true" * Migration changes (#1466) * Migrations folder structure * Change migrations path * Remove unwanted utilities * Remove utilities * Add version in comment section of migrations * Check if the table exists or not * Adding if exist condition for update * Rename the fields migrations * MIgration changes * Remove check for libapache2_mod_php (#1479) The Apache PHP module is needed in order to run PHP from Apache. This information is returned from PHP, so if this module isn't loaded, this whole endpoint wouldn't do anything. If this endpoint works, we already know that libapache2-mod-php is working as expected. (Also, extension_loaded("libapache2-mod-php") never seems to be true. * Rename page->module (#1485) * Don't raise the required error if the field has a default value (#1487) * Replace nav_override with collection / module listing * Fix #1488 (#1489) * Fix #1462 [Authentication API return user object] (#1490) * Fix #1483 [activity_skip doesnt work on delete file] (#1491) * Fix width on wrong value * Fix collection listing not using right options * Update the options based on seeder * Rework the thumbnailer (#1467) * Thumbnail whitelist development * Image and thumbnail URL changes and validations * Assets endpoints in thumbnail * Default thumbnail URL changes and other changes * Removed thumbnail in public * Requested changes in thumbnailer * Remove key from folder name * Provide the support for both keys - system and whitelist * Return all the thumbnail - including system as well as whitelisted * Use the shorthand for width, height, quality and fit * Use the shorthands for params * Update AssetService.php * Update the error message * MIgration changes (#1495) * MIgration changes * Update the sorting ordeR * Render original path as full_url * Use color interface for project color * Update migrations for setings * Fix thumbnailer enabled check + * generation * Cleanup settings migrations * Rename thumbnail_whitelist to asset_whitelist * Fix non-key whitelisted asset * Update migrations * Add contain constraint * Remove hardcoded settings validation * Remove default project based empty folders * Use generated as default thumbnail location * Config updates (#1484) * Migrations folder structure * Change migrations path * Remove unwanted utilities * Remove utilities * Add version in comment section of migrations * Check if the table exists or not * Adding if exist condition for update * Rename the fields migrations * Rename api-sample.php to _example.php * Don't return ignored files * Move env out of app config category * Remove timezone flag from config * Move logger config out of settings key * [WIP] Start on new example config file * Change order + remove comments from config stub * Get rid of unused `feedback` config section * Update example config file * Added missing comma * Added missing comma * Remove migration * Adding support for _ project * Add comment for condition * Update Server.php * Ignore _ prefixed config files everywhere * Make durations readonly * Use tags for ip whitelist * Clear whitespace + set duration to readonly * Fix #1497 [V8 fresh install is broken] * Add migration for migrating advanced wysiwyg to wysiwyg Fixes https://github.com/directus/directus/issues/2465 * Fix deleting file type fields from collection Fixes #1503 * Update the thumbnailer (#1506) * File name changes and thumbnailer changes * Thumbnail related changes * name changes * Fix typo * Thumbnail changes * Combine migration files * Replace the file delete code from basetablegateway to fileservice * Tweak migrations * Set uuid to default field format * Don't change primary key of directus_files * Fix content-disposition header + last modified for originals and thumbnails * Don't return thumbnails if the asset type isn't an image * Set duration to readonly * Don't try reading non-images files with Intervention * Prefer application/pdf over application/acrobat * Update repeater settings for asset whitelist * Fix renaming files * Don't return thumbnail info for svgs * update example config comments * remove leading slash from example * Have migrations (#1509) * Put old migrations back * Upgrade migrations * Various tweaks * Fix private hash requirement flag The API still throw a required error, even though its a generated field * Fix settings * Rework order of migrations * Beautify directus_files Beautify directus_files Beautify directus_files Beautify directus_files Beautify directus_files Beautify directus_files Beautify directus_files Beautify directus_files Beautify directus_files * Remove nav_blacklist, add enforce_2fa * Tweak settings of timeline * Get rid of activity icon * Use system collections in directus activity main view * Handle error : Use of undefined constant ERROR_MESSAGE * Rebuild the 2FA query (#1510) * Redevelop the 2FA query * Dynamic name of table * Fix #1508 [Deleting a file attached to an item deletes the item] (#1512) * Update type of enforce_2fa from array to boolean * Update type of enforce_2fa from array to boolean * Fix #1473 [Remove cookie if token is invalid] (#1513) * Update README.md * Update README.md * Add uploads folder to base structure * Fix _.php config name + remove duplicate code * Also migrate wysiwyg_full * Bump version --- .gitignore | 2 +- README.md | 178 +- config/_example.php | 170 ++ config/api_sample.php | 174 -- .../20180220023138_create_activity_table.php | 82 - ...23152_create_collections_presets_table.php | 83 - ...0180220023157_create_collections_table.php | 71 - .../20180220023202_create_fields_table.php | 115 - .../20180220023208_create_files_table.php | 121 - .../20180220023213_create_folders_table.php | 50 - .../20180220023217_create_roles_table.php | 75 - ...0180220023226_create_permissions_table.php | 99 - .../20180220023232_create_relations_table.php | 55 - .../20180220023238_create_revisions_table.php | 66 - .../20180220023243_create_settings_table.php | 47 - .../20180220023248_create_users_table.php | 143 -- .../20190912072543_create_user_sessions.php | 76 - .../20190917090849_create_web_hooks.php | 68 - .../db/seeds/CollectionPresetsSeeder.php | 85 - migrations/db/seeds/FieldsSeeder.php | 1915 --------------- migrations/db/seeds/RelationsSeeder.php | 80 - migrations/db/seeds/RolesSeeder.php | 33 - migrations/db/seeds/SettingsSeeder.php | 111 - .../20180220023123_create_fields_table.php | 252 ++ .../20180220023138_create_activity_table.php | 220 ++ ...23152_create_collections_presets_table.php | 218 ++ ...0180220023157_create_collections_table.php | 167 ++ .../20180220023208_create_files_table.php | 399 ++++ .../20180220023213_create_folders_table.php | 69 + .../20180220023217_create_roles_table.php | 221 ++ ...0180220023226_create_permissions_table.php | 189 ++ .../20180220023232_create_relations_table.php | 158 ++ .../20180220023238_create_revisions_table.php | 127 + .../20180220023243_create_settings_table.php | 467 ++++ .../20180220023248_create_users_table.php | 551 +++++ .../20190912072543_create_user_sessions.php | 42 +- .../20190917090849_create_webhooks.php} | 141 +- migrations/migrations.php | 3 +- migrations/migrations.upgrades.php | 3 +- .../20181022175715_upgrade_070003.php | 0 .../20181102153600_timezone_choices.php | 0 .../20181105165224_upgrade_070006.php | 0 .../20181122195602_locale_interface.php | 0 .../20181123171520_remove_scope.php | 0 ...4720_add_trusted_proxies_setting_field.php | 0 ...22023800_add_project_url_setting_field.php | 0 ...042755_increase_users_last_page_length.php | 0 ...90104155309_add_users_email_validation.php | 0 ...190111193724_add_app_url_setting_field.php | 0 ...90111212736_add_missing_settings_field.php | 0 .../20190118181424_add_roles_users_field.php | 0 ...0190130215921_add_files_checksum_field.php | 0 .../20190318173400_add_nav_override.php | 0 ...190412122400_set_password_type_to_hash.php | 0 .../20190412123000_use_file_interface.php | 0 .../20190412145800_set_o2m_options_roles.php | 0 .../20190415125300_set_width.php | 0 .../20190419154400_settings_fields.php | 0 .../20190419161200_collection_notes.php | 0 .../20190419173000_misc_required_fields.php | 0 .../{schemas => }/20190422131600_use_json.php | 14 +- ...et_nullable_value_field_settings_table.php | 0 .../20190520094300_use_timeline.php | 0 ...90614103321_add_users_2fa_secret_field.php | 0 ...90618190024_add_enforce_2fa_role_field.php | 0 ...90626114228_add_file_naming_in_setting.php | 0 ...323_add_login_attempts_allowed_setting.php | 0 ...0190704063752_update_istanbul_timezone.php | 0 ...90708095522_add_file_extension_setting.php | 0 ...190709053719_add_file_max_size_setting.php | 0 ...0232_password_validation_setting_field.php | 0 ...26064001_update_note_for_default_limit.php | 0 ...819070856_update_directus_fields_field.php | 0 ...1123053252_update_directus_files_field.php | 189 ++ .../20191129123300_use_new_wysiwyg.php | 24 + .../20191202164200_add_user_sessions.php | 58 + .../upgrades/20191202164201_add_webhooks.php | 50 + .../20191202164202_remove_activity_seen.php | 15 + .../20191202164203_convert_user_roles.php | 40 + .../20191202164204_update_directus_users.php | 39 + ...0191202164205_update_directus_settings.php | 123 + .../20191202164206_update_directus_files.php | 59 + .../20191202164207_update_directus_roles.php | 59 + ...0191202164208_reset_directus_relations.php | 98 + .../20191202164209_reset_directus_fields.php | 2068 +++++++++++++++++ ...14095509_update_directus_user_sessions.php | 48 - .../20191001092213_add_project_settings.php | 61 - .../20191002070945_rename_settings.php | 31 - ...te_type_for_uploaded_by_directus_files.php | 20 - ...15_update_general_setting_variabe_name.php | 100 - ...locale_and_telemetry_to_settings_table.php | 32 - ...1112175432_remove_activity_seen_fields.php | 48 - ...191113083711_update_current_migrations.php | 665 ------ .../20191114095051_update_user_role_type.php | 86 - ...0191118181240_add_theme_field_for_user.php | 56 - .../extensions/custom/modules}/.gitkeep | 0 public/thumbnail/.htaccess | 2 - public/thumbnail/index.php | 90 - .../custom/pages => uploads}/.gitkeep | 0 public/uploads/_/originals/.gitkeep | 0 public/uploads/_/originals/.htaccess | 24 - public/uploads/_/thumbnails/.gitkeep | 0 src/core/Directus/Application/Application.php | 2 +- .../Application/CoreServicesProvider.php | 106 +- .../Middleware/ResponseCacheMiddleware.php | 38 +- .../Exception/TFAEnforcedException.php | 2 +- src/core/Directus/Config/Schema/Schema.php | 17 +- .../Console/Modules/InstallModule.php | 48 +- .../TableGateway/BaseTableGateway.php | 97 +- .../TableGateway/RelationalTableGateway.php | 51 +- src/core/Directus/Filesystem/Files.php | 47 +- src/core/Directus/Filesystem/Thumbnailer.php | 110 +- src/core/Directus/GraphQL/FieldsConfig.php | 5 +- .../Directus/Services/AbstractService.php | 29 +- src/core/Directus/Services/AssetService.php | 434 ++++ src/core/Directus/Services/FilesServices.php | 89 +- .../{PagesService.php => ModulesService.php} | 6 +- src/core/Directus/Services/ProjectService.php | 12 +- src/core/Directus/Services/ServerService.php | 14 +- .../Directus/Services/SettingsService.php | 2 + src/core/Directus/Services/TablesService.php | 20 +- src/core/Directus/Services/UsersService.php | 37 +- src/core/Directus/Util/DateTimeUtils.php | 15 +- .../Util/Installation/InstallerUtils.php | 36 +- .../Util/Installation/stubs/config.stub | 153 +- src/core/Directus/Util/MimeTypeUtils.php | 2 +- src/endpoints/Assets.php | 38 + src/endpoints/Auth.php | 12 +- src/endpoints/Fields.php | 5 +- src/endpoints/Files.php | 10 +- src/endpoints/{Pages.php => Modules.php} | 6 +- src/endpoints/ProjectHome.php | 2 +- src/endpoints/Server.php | 30 +- src/endpoints/Settings.php | 7 +- src/helpers/all.php | 14 +- src/helpers/app.php | 25 +- src/helpers/file.php | 125 +- src/helpers/settings.php | 7 +- src/web.php | 13 +- 139 files changed, 7217 insertions(+), 5674 deletions(-) create mode 100644 config/_example.php delete mode 100644 config/api_sample.php delete mode 100644 migrations/db/schemas/20180220023138_create_activity_table.php delete mode 100644 migrations/db/schemas/20180220023152_create_collections_presets_table.php delete mode 100644 migrations/db/schemas/20180220023157_create_collections_table.php delete mode 100644 migrations/db/schemas/20180220023202_create_fields_table.php delete mode 100644 migrations/db/schemas/20180220023208_create_files_table.php delete mode 100644 migrations/db/schemas/20180220023213_create_folders_table.php delete mode 100644 migrations/db/schemas/20180220023217_create_roles_table.php delete mode 100644 migrations/db/schemas/20180220023226_create_permissions_table.php delete mode 100644 migrations/db/schemas/20180220023232_create_relations_table.php delete mode 100644 migrations/db/schemas/20180220023238_create_revisions_table.php delete mode 100644 migrations/db/schemas/20180220023243_create_settings_table.php delete mode 100644 migrations/db/schemas/20180220023248_create_users_table.php delete mode 100644 migrations/db/schemas/20190912072543_create_user_sessions.php delete mode 100644 migrations/db/schemas/20190917090849_create_web_hooks.php delete mode 100644 migrations/db/seeds/CollectionPresetsSeeder.php delete mode 100644 migrations/db/seeds/FieldsSeeder.php delete mode 100644 migrations/db/seeds/RelationsSeeder.php delete mode 100644 migrations/db/seeds/RolesSeeder.php delete mode 100644 migrations/db/seeds/SettingsSeeder.php create mode 100644 migrations/install/20180220023123_create_fields_table.php create mode 100644 migrations/install/20180220023138_create_activity_table.php create mode 100644 migrations/install/20180220023152_create_collections_presets_table.php create mode 100644 migrations/install/20180220023157_create_collections_table.php create mode 100644 migrations/install/20180220023208_create_files_table.php create mode 100644 migrations/install/20180220023213_create_folders_table.php create mode 100644 migrations/install/20180220023217_create_roles_table.php create mode 100644 migrations/install/20180220023226_create_permissions_table.php create mode 100644 migrations/install/20180220023232_create_relations_table.php create mode 100644 migrations/install/20180220023238_create_revisions_table.php create mode 100644 migrations/install/20180220023243_create_settings_table.php create mode 100644 migrations/install/20180220023248_create_users_table.php rename migrations/{upgrades/schemas => install}/20190912072543_create_user_sessions.php (71%) rename migrations/{upgrades/schemas/20190917090849_create_web_hooks.php => install/20190917090849_create_webhooks.php} (59%) rename migrations/upgrades/{schemas => }/20181022175715_upgrade_070003.php (100%) rename migrations/upgrades/{schemas => }/20181102153600_timezone_choices.php (100%) rename migrations/upgrades/{schemas => }/20181105165224_upgrade_070006.php (100%) rename migrations/upgrades/{schemas => }/20181122195602_locale_interface.php (100%) rename migrations/upgrades/{schemas => }/20181123171520_remove_scope.php (100%) rename migrations/upgrades/{schemas => }/20181210204720_add_trusted_proxies_setting_field.php (100%) rename migrations/upgrades/{schemas => }/20181222023800_add_project_url_setting_field.php (100%) rename migrations/upgrades/{schemas => }/20181227042755_increase_users_last_page_length.php (100%) rename migrations/upgrades/{schemas => }/20190104155309_add_users_email_validation.php (100%) rename migrations/upgrades/{schemas => }/20190111193724_add_app_url_setting_field.php (100%) rename migrations/upgrades/{schemas => }/20190111212736_add_missing_settings_field.php (100%) rename migrations/upgrades/{schemas => }/20190118181424_add_roles_users_field.php (100%) rename migrations/upgrades/{schemas => }/20190130215921_add_files_checksum_field.php (100%) rename migrations/upgrades/{schemas => }/20190318173400_add_nav_override.php (100%) rename migrations/upgrades/{schemas => }/20190412122400_set_password_type_to_hash.php (100%) rename migrations/upgrades/{schemas => }/20190412123000_use_file_interface.php (100%) rename migrations/upgrades/{schemas => }/20190412145800_set_o2m_options_roles.php (100%) rename migrations/upgrades/{schemas => }/20190415125300_set_width.php (100%) rename migrations/upgrades/{schemas => }/20190419154400_settings_fields.php (100%) rename migrations/upgrades/{schemas => }/20190419161200_collection_notes.php (100%) rename migrations/upgrades/{schemas => }/20190419173000_misc_required_fields.php (100%) rename migrations/upgrades/{schemas => }/20190422131600_use_json.php (95%) rename migrations/upgrades/{schemas => }/20190426156200_set_nullable_value_field_settings_table.php (100%) rename migrations/upgrades/{schemas => }/20190520094300_use_timeline.php (100%) rename migrations/upgrades/{schemas => }/20190614103321_add_users_2fa_secret_field.php (100%) rename migrations/upgrades/{schemas => }/20190618190024_add_enforce_2fa_role_field.php (100%) rename migrations/upgrades/{schemas => }/20190626114228_add_file_naming_in_setting.php (100%) rename migrations/upgrades/{schemas => }/20190702092323_add_login_attempts_allowed_setting.php (100%) rename migrations/upgrades/{schemas => }/20190704063752_update_istanbul_timezone.php (100%) rename migrations/upgrades/{schemas => }/20190708095522_add_file_extension_setting.php (100%) rename migrations/upgrades/{schemas => }/20190709053719_add_file_max_size_setting.php (100%) rename migrations/upgrades/{schemas => }/20190722110232_password_validation_setting_field.php (100%) rename migrations/upgrades/{schemas => }/20190726064001_update_note_for_default_limit.php (100%) rename migrations/upgrades/{schemas => }/20190819070856_update_directus_fields_field.php (100%) create mode 100644 migrations/upgrades/20191123053252_update_directus_files_field.php create mode 100644 migrations/upgrades/20191129123300_use_new_wysiwyg.php create mode 100644 migrations/upgrades/20191202164200_add_user_sessions.php create mode 100644 migrations/upgrades/20191202164201_add_webhooks.php create mode 100644 migrations/upgrades/20191202164202_remove_activity_seen.php create mode 100644 migrations/upgrades/20191202164203_convert_user_roles.php create mode 100644 migrations/upgrades/20191202164204_update_directus_users.php create mode 100644 migrations/upgrades/20191202164205_update_directus_settings.php create mode 100644 migrations/upgrades/20191202164206_update_directus_files.php create mode 100644 migrations/upgrades/20191202164207_update_directus_roles.php create mode 100644 migrations/upgrades/20191202164208_reset_directus_relations.php create mode 100644 migrations/upgrades/20191202164209_reset_directus_fields.php delete mode 100644 migrations/upgrades/schemas/20190914095509_update_directus_user_sessions.php delete mode 100644 migrations/upgrades/schemas/20191001092213_add_project_settings.php delete mode 100644 migrations/upgrades/schemas/20191002070945_rename_settings.php delete mode 100644 migrations/upgrades/schemas/20191007113144_update_type_for_uploaded_by_directus_files.php delete mode 100644 migrations/upgrades/schemas/20191105063515_update_general_setting_variabe_name.php delete mode 100644 migrations/upgrades/schemas/20191112161523_add_locale_and_telemetry_to_settings_table.php delete mode 100644 migrations/upgrades/schemas/20191112175432_remove_activity_seen_fields.php delete mode 100644 migrations/upgrades/schemas/20191113083711_update_current_migrations.php delete mode 100644 migrations/upgrades/schemas/20191114095051_update_user_role_type.php delete mode 100644 migrations/upgrades/schemas/20191118181240_add_theme_field_for_user.php rename {migrations/upgrades/seeds => public/extensions/custom/modules}/.gitkeep (100%) delete mode 100644 public/thumbnail/.htaccess delete mode 100644 public/thumbnail/index.php rename public/{extensions/custom/pages => uploads}/.gitkeep (100%) delete mode 100644 public/uploads/_/originals/.gitkeep delete mode 100644 public/uploads/_/originals/.htaccess delete mode 100644 public/uploads/_/thumbnails/.gitkeep create mode 100644 src/core/Directus/Services/AssetService.php rename src/core/Directus/Services/{PagesService.php => ModulesService.php} (67%) create mode 100644 src/endpoints/Assets.php rename src/endpoints/{Pages.php => Modules.php} (81%) diff --git a/.gitignore b/.gitignore index c59f3450e6..78ddb63a76 100644 --- a/.gitignore +++ b/.gitignore @@ -24,7 +24,7 @@ deploy.* # Ignore configuration files /config/* -!/config/api_sample.php +!/config/_example.php # PHPUnit /phpunit.xml diff --git a/README.md b/README.md index ca7a23c5c9..a889617275 100644 --- a/README.md +++ b/README.md @@ -1,173 +1,27 @@ -

- - Directus Logo - -

+

+ Directus Logo  Directus API

-

 

+> Looking for the full Directus suite? Checkout [the `directus/directus` repo](https://github.com/directus/directus)! -

- The All-New Directus 7
Future-Proof Headless CMS -

+## Description -

- Website β€’ - Docs β€’ - API Reference β€’ - User Guide β€’ - Demo β€’ - Contribute β€’ - Twitter -

+The Directus API is a PHP powered REST / GraphQL API that acts as a layer on top of a relational database. -

 

+## Installation / Usage -> _The Directus 7 App has been rebuilt from the ground-up in Vue.js and decoupled from our new "versionless" API. Both can easily be customized and extended to suit your project's needs._ +**NOTE**: Unless you're contributing to the project, you shouldn't build the API from source. Use [`directus/directus`](/directus/directus) instead. -

 

+1. Clone the repo +2. Install the depencencies using `composer`: `composer install` +3. Run the application using any local server, like MAMP, DDEV, Docker, or any other (preferably) Apache installation. -## 🐰 Introduction +## Core Team -Directus is an open-source suite of software that provides an instant API wrapper for SQL databases and an intuitive Admin App for non-technical users to manage that content. It's like a safe, friendly, and super-powered "database client" (eg: _PHP-my-Admin_ or _Sequel Pro_). Created in 2004, our premium platform powers hundreds-of-thousands of data-driven applications around the world. With our JSON API, webhooks, and complete control over where and how your content is used β€” what will you build with Directus? +* [Ben Haynes](https://github.com/benhaynes) _(Project Lead)_ +* [Rijk van Zanten](https://github.com/rijkvanzanten) _(Tech Lead)_ -* **[Directus API](https://github.com/directus/api)** β€” Wraps any new or existing SQL database with RESTful JSON endpoints for connecting content anywhere: websites, native apps, wearables, IoT devices, kiosks, or anything else! -* **[Directus Admin App](https://github.com/directus/app)** β€” A friendly admin interface built with Vue.js that works in conjunction with our API to allow non-technical users to manage database content and digital assets. -* **[Directus Suite](https://github.com/directus/directus)** A package that combines our API, Admin App, and all dependencies for quick and easy installation on most servers. +[Advisors, Sponsors, Partners, and Key Contributors](https://directus.io/organization.html#the-team) -

 

+## License -## ✨ Key Concepts - -### Database-First - -Directus follows a database-first approach, storing all of your data _unaltered_ in pure SQL databases with that can be completely customized. - -#### Access and Optimization - -Directus mirrors _your_ actual database so it will automatically stay in sync with any changes made directly to the database! With the full power of SQL unlocked, you can: - -1. Architect your actual database with meaningful table and column names -2. Infinitely optimize with indexing, datatypes, lengths, defaults, keys, encoding, etc -3. Update your database schema at any point and Directus will instantly reflect changes -4. Create, update, and delete content directly from the database - -#### Direct Access - -This database-first approach means that you have the option to completely bypass Directus if needed. Connecting your application _directly_ to the database means Directus is completely bypassed, removing even the slightest possiblility of a bottleneck, and giving you the unbridled power of complex SQL queries. - -#### Portability and Transparency - -Directus is _not_ a black-box system. There is nothing proprietary or opinionated about how Directus stores your content so you're never locked-in or locked out. Import existing SQL to get started quickly, and rest assured that you can also export your unaltered content as vanilla SQL at any point. You can also self-host the entire suite on your own servers if needed or use our hosted Cloud service. - -#### Complex Relationships - -Whether you need many-to-one, one-to-many, many-to-many, or something completely different... Directus has you covered. You can interrelate database fields, then fetch deeply nested data using our robust dot-notation parameters. - -### Simple, Modular and Extensible - -We've intentionally kept our codebase as simple and lightweight as possible. Every aspect of Directus has been modularized, with many options for extending, overriding, or even bypassing the core system. Choose your auth providers, storage adapters, content interfaces, data presentation, and more. We also have webhooks, event hooks, API response filters, custom endpoints, CSS/JS override files, and much more. - -Furthermore, because the codebase has been internally decoupled, Directus supports full multitenancy. You can use a single Directus App to manage multiple Directus API instances, and each API instance can manage multiple databases (projects or environments). - -### Internationalization and Accessibility - -Directus allows you to manage multilingual content in as many languages as your project needs. And no matter what language(s) your organization requires, our Admin App supports a growing number of locales. We've also paid close attention to our Admin App's interface to ensure it is as clear and accessible as possible for all users. - -

 

- -## πŸ“– Documentation - -* [What is Directus?](https://docs.directus.io/getting-started/introduction.html#what-is-directus) -* [Installing the Directus Suite](https://docs.directus.io/getting-started/installation.html) -* [Extending Directus](https://docs.directus.io/extensions/) -* Directus App - * [App Docs](https://docs.directus.io/advanced/app/standalone.html) - * [User Guide](https://docs.directus.io/guides/user-guide.html) - * [Install the App](https://docs.directus.io/advanced/app/standalone.html#installation) -* Directus API - * [API Docs](https://docs.directus.io/advanced/api/standalone.html) - * [API Reference](https://docs.directus.io/api/reference.html) - * [Install the API](https://docs.directus.io/advanced/api/standalone.html#installation) -* Tutorials - * [Tutorials](https://medium.com/directus) - * [Videos](https://www.youtube.com/playlist?list=PLD--x9rY3ZL31stRPkA4FdGC4idIM-8-d) - -

 

- -## 🀲 Help & Resources - -### Technical Support - -* **Community Support** β€” For help with open-source instances please post questions with the `directus` tag on [Stack Overflow](https://stackoverflow.com/questions/tagged/directus) or chat with members of our online community. -* **Premium Support** β€” Directus Cloud customers, Patreon Sponsors, and those paying for hourly support all have access to our Live support over our [Live Chat](https://directus.io) or [Email](mailto:support@directus.io). - -### Community - -* **[Slack](https://directus.chat)** β€” Come join over a thousand members discussing the future of Directus. Our helpful members are also quick to offer advice for simple questions you may have while getting started. -* **[Twitter](https://twitter.com/directus)** β€” Follow us on Twitter to be the first to hear about product updates, see sneak peeks of new features, and vote on polls regarding the future of our platform. - -### GitHub Tickets - -* **Reporting Bugs** β€” If you believe you've found a bug in the Directus Core codebase, please submit new tickets to either the [App](https://github.com/directus/app/issues/new?template=Bug_report.md) or the [API](https://github.com/directus/api/issues/new?template=Bug_report.md). **For all security related issues, please chat with us directly through [directus.io](https://directus.io/).** -* **Requesting Features** β€” Feature requests are managed as GitHub issues within the appropriate Directus repository. Before making a new submission, first [browse existing feature requests](https://github.com/directus/app/issues?q=is%3Aissue+is%3Aopen+sort%3Areactions-%2B1-desc+label%3Aenhancement) using the `enhancement` label. If you find a similar request, simply vote for it using the :+1: or :-1: reactions and add any additional context in the comments. If _not_, [add a new feature request](https://github.com/directus/app/issues/new?template=Feature_request.md) by completing the provided template. - -### Online Demos - -We have two online demos available so you can easily check out Directus in action. These demos are public and is therefore susceptible to trolls who think it's funny to write offensive things or change the master user password. The entire database is reset each hour to mitigate this. The login credentials for both demos: `admin@example.com` and `password` - -* **[Stable](https://directus.app)** β€” This demo showcases the [latest release](https://github.com/directus/directus/releases/latest) of the Directus suite. -* **[Nightly](https://nightly.directus.app)** β€” This demo uses the [latest commits](https://github.com/directus/directus/commits/master) from the `master` branch. - -

 

- -## ❀️ Supporting Directus - -Directus is a GPLv3-licensed open source project with development made possible by support from our core team, contributors, and sponsors. It's not easy building premium open-source software; if you would like to help ensure Directus stays free, please consider becoming a sponsor. - -* [Become a backer or sponsor through Patreon](https://www.patreon.com/directus) -* [One-time donation through PayPal](https://www.paypal.me/supportdirectus) -* [Other ways to help](https://docs.directus.io/getting-started/supporting-directus.html) - - -### Contributing - -We love pull-requests! To work on Directus you'll need to install it locally from source by following the instructions below. Submit all pull-requests to the `develop` branch of our `api` and `app` repositories. - -* [Setup API Development Environment](https://docs.directus.io/advanced/source.html#api-source) -* [Setup App Development Environment](https://docs.directus.io/advanced/source.html#application-source) - -If you want to dive right into the code and skip the manual setup of your development environment you can also spin up fully functional browser based development environments with a single click: - -* [Start API Gitpod Workspace](https://gitpod.io/#https://github.com/directus/api) -* [Start APP Gitpod Workspace](https://gitpod.io/#https://github.com/directus/app) - -### Sponsors - -[RANGER Studio](http://rangerstudio.com), Bas Jansen - -### Core Team - - - - - - -
-
- Ben Haynes

- Project Lead -
-
- Rijk van Zanten

- App Lead -
- -**[Advisors, Sponsors, Partners, and Key Contributors](https://directus.io/organization.html#the-team)** - -

 

- ----- - -

- Directus is released under the GPLv3 license. RANGER Studio LLC owns all Directus trademarks and logos on behalf of our project's community. Copyright Β© 2006-2018, RANGER Studio LLC. -

+Directus is released under the [GPLv3](http://www.gnu.org/copyleft/gpl.html) license. [RANGER Studio LLC](https://rangerstudio.com) owns all Directus trademarks and logos on behalf of our project's community. Copyright Β© 2006-2019, [RANGER Studio LLC](https://rangerstudio.com). diff --git a/config/_example.php b/config/_example.php new file mode 100644 index 0000000000..128fd3541e --- /dev/null +++ b/config/_example.php @@ -0,0 +1,170 @@ + [ + 'type' => 'mysql', // Only mysql is supported + 'host' => 'localhost', + 'port' => 3306, + 'name' => 'directus', + 'username' => 'root', + 'password' => 'root', + 'engine' => 'InnoDB', + 'charset' => 'utf8mb4', + // 'socket' => '', // Path to socket. Remove the `host` key above when using sockets + // 'driver_options' => [ // Other MYSQL_PDO options. Can be used to connect to the database + // // over an encrypted connection. For more information, see + // // https://www.php.net/manual/en/ref.pdo-mysql.php#pdo-mysql.constants + // PDO::MYSQL_ATTR_SSL_CAPATH => '/etc/ssl/certs', + // ] + ], + + 'cors' => [ + 'enabled' => true, // Enable or disable all CORS headers + 'origin' => ['*'], // Access-Control-Allow-Origin + 'methods' => [ // Access-Control-Allow-Methods + 'GET', + 'POST', + 'PUT', + 'PATCH', + 'DELETE', + 'HEAD', + ], + 'headers' => [], // Access-Control-Allow-Headers + 'exposed_headers' => [], // Access-Control-Expose-Headers + 'max_age' => null, // Access-Control-Allow-Max-Age + 'credentials' => false, // Access-Control-Allow-Credentials + ], + + 'rate_limit' => [ + 'enabled' => false, // Enable or disable all rate limiting + 'limit' => 100, // Number of requests allowed... + 'interval' => 60, // ...during this interval (in seconds) + 'adapter' => 'redis', // Where to save the rate limit tmp data + 'host' => '127.0.0.1', + 'port' => 6379, + 'timeout' => 10 // Timeout from API to rate limit storage adapter + ], + + 'storage' => [ + 'adapter' => 'local', // What storage adapter to use for files + // Defaults to the local filesystem. Other natively supported + // options include: Amazon S3, Aliyun OSS + // You'll need to require the correct flysystem adapters through Composer + // See https://docs.directus.io/extensions/storage-adapters.html#using-aws-s3 + + 'root' => 'public/uploads/project-name/originals', // Where files are stored on disk + 'thumb_root' => 'public/uploads/project-name/thumbnails', // Where thumbnails are stored on disk + 'root_url' => '/uploads/project-name/originals', // Where files are accessed over the web + + 'proxy_downloads' => false, // Use an internal proxy for downloading all files + + // S3 + //////////////////////////////////////// + // 'key' => 's3-key', + // 'secret' => 's3-secret', + // 'region' => 's3-region', + // 'version' => 's3-version', + // 'bucket' => 's3-bucket', + // 'options' => [ + // 'ACL' => 'public-read', + // 'Cache-Control' => 'max-age=604800' + // ], + // 'endpoint' => 's3-endpoint', + + // Aliyun OSS + //////////////////////////////////////// + // 'OSS_ACCESS_ID' => 'aliyun-oss-id', + // 'OSS_ACCESS_KEY' => 'aliyun-oss-key', + // 'OSS_ENDPOINT' => 'aliyun-oss-endpoint', + // 'OSS_BUCKET' => 'aliyun-oss-bucket', + ], + + 'mail' => [ + 'default' => [ + 'transport' => 'smtp', // How to send emails. Supports `smtp` and `sendmail` + 'from' => 'no-reply@example.com', // The sender of the email + + // SMTP + //////////////////////////////////////// + 'host' => 'smtp.example.com', + 'port' => 25, + 'username' => 'smtp-user', + 'password' => 'd1r3ctu5', + 'encryption' => 'tls' + ], + ], + + 'cache' => [ + 'enabled' => false, // Cache all API responses + 'response_ttl' => 3600, // Keep the cache for n seconds + 'pool' => [ + 'adapter' => 'apc', // What adapter to use to store the cache in + // Supports: apc, apcu, filesystem, memcached, + // memcache, redis + + // Filesystem + //////////////////////////////////////// + // 'path' => '../cache/', + + // memcached, memcache, redis + //////////////////////////////////////// + // 'host' => 'localhost', + // 'port' => 11211, + ], + ], + + 'auth' => [ + 'secret_key' => '1234', // Used in the oAuth flow + 'public_key' => '9876', + 'social_providers' => [ + // 'okta' => [ + // 'client_id' => '', + // 'client_secret' => '', + // 'base_url' => 'https://dev-000000.oktapreview.com/oauth2/default' + // ], + // 'github' => [ + // 'client_id' => '', + // 'client_secret' => '' + // ], + // 'facebook' => [ + // 'client_id' => '', + // 'client_secret' => '', + // 'graph_api_version' => 'v2.8', + // ], + // 'google' => [ + // 'client_id' => '', + // 'client_secret' => '', + // 'hosted_domain' => '*', + // 'use_oidc_mode' => true, + // ], + // 'twitter' => [ + // 'identifier' => '', + // 'secret' => '' + // ] + ] + ], + + 'hooks' => [ // https://docs.directus.io/extensions/hooks.html#creating-hooks + 'actions' => [], + 'filters' => [], + ], + + 'tableBlacklist' => [], // What tables to globally ignore within Directus + + 'env' => 'production', // production, development, or staging + // Production silences stack traces and error details in API output + + 'logger' => [ + 'path' => '../logs', // Where to save warning and error logs for the API + ], + + 'feedback' => [ + 'token' => '123', // Not currently used + 'login' => true // Not currently used + ], +]; diff --git a/config/api_sample.php b/config/api_sample.php deleted file mode 100644 index 760dfbc9a9..0000000000 --- a/config/api_sample.php +++ /dev/null @@ -1,174 +0,0 @@ - [ - 'env' => 'production', - 'timezone' => 'America/New_York' - ], - - 'settings' => [ - 'logger' => [ - 'path' => __DIR__ . '/../logs', - ], - ], - - 'database' => [ - 'type' => 'mysql', - 'host' => 'localhost', - 'port' => 3306, - 'name' => 'directus', - 'username' => 'root', - 'password' => 'root', - 'engine' => 'InnoDB', - 'charset' => 'utf8mb4', - // When using unix socket to connect to the database the host attribute should be removed - // 'socket' => '/var/lib/mysql/mysql.sock', - 'socket' => '', - // Connect over TLS by using the appropriate PDO_MySQL constants: - // https://www.php.net/manual/en/ref.pdo-mysql.php#pdo-mysql.constants - //'driver_options' => [ - // PDO::MYSQL_ATTR_SSL_CAPATH => '/etc/ssl/certs', - //] - ], - - 'cache' => [ - 'enabled' => false, - 'response_ttl' => 3600, // seconds - // 'pool' => [ - // 'adapter' => 'apc' - // ], - // 'pool' => [ - // 'adapter' => 'apcu' - // ], - // 'pool' => [ - // 'adapter' => 'filesystem', - // 'path' => '../cache/', // relative to the api directory - // ], - // 'pool' => [ - // 'adapter' => 'memcached', - // //'url' => 'localhost:11211;localhost:11212' - // 'host' => 'localhost', - // 'port' => 11211 - // ], - // 'pool' => [ - // 'adapter' => 'memcache', - // 'url' => 'localhost:11211;localhost:11212' - // //'host' => 'localhost', - // //'port' => 11211 - //], - // 'pool' => [ - // 'adapter' => 'redis', - // 'host' => 'localhost', - // 'port' => 6379 - // ], - ], - - 'storage' => [ - 'adapter' => 'local', - // The storage root is the directus root directory. - // All path are relative to the storage root when the path is not starting with a forward slash. - // By default the uploads directory is located at the directus public root - // An absolute path can be used as alternative. - 'root' => 'public/uploads/_/originals', - // This is the url where all the media will be pointing to - // here is where Directus will assume all assets will be accessed - // Ex: (yourdomain)/uploads/_/originals - 'root_url' => '/uploads/_/originals', - // Same as "root", but for the thumbnails - 'thumb_root' => 'public/uploads/_/thumbnails', - // 'key' => 's3-key', - // 'secret' => 's3-secret', - // 'region' => 's3-region', - // 'version' => 's3-version', - // 'bucket' => 's3-bucket', - // 'options' => ['ACL' => 'public-read', 'Cache-Control' => 'max-age=604800'] - // Set custom S3 endpoint - // 'endpoint' => 's3-endpoint', - // 'OSS_ACCESS_ID' => 'aliyun-oss-id', - // 'OSS_ACCESS_KEY' => 'aliyun-oss-key', - // 'OSS_ENDPOINT' => 'aliyun-oss-endpoint', - // 'OSS_BUCKET' => 'aliyun-oss-bucket' - // Use an internal proxy for downloading all files - //'proxy_downloads' => false, - ], - - 'mail' => [ - 'default' => [ - 'transport' => 'sendmail', - 'from' => 'admin@example.com' - ], - ], - - 'cors' => [ - 'enabled' => true, - 'origin' => ['*'], - 'methods' => [ - 'GET', - 'POST', - 'PUT', - 'PATCH', - 'DELETE', - 'HEAD', - ], - 'headers' => [], - 'exposed_headers' => [], - 'max_age' => null, // in seconds - 'credentials' => false, - ], - - 'rate_limit' => [ - 'enabled' => false, - 'limit' => 100, // number of request - 'interval' => 60, // seconds - 'adapter' => 'redis', - 'host' => '127.0.0.1', - 'port' => 6379, - 'timeout' => 10 - ], - - 'hooks' => [ - 'actions' => [], - 'filters' => [], - ], - - 'feedback' => [ - 'token' => 'a-kind-of-unique-token', - 'login' => true - ], - - // These tables will not be loaded in the directus schema - 'tableBlacklist' => [], - - 'auth' => [ - 'secret_key' => '', - 'public_key' => '', - 'social_providers' => [ - // 'okta' => [ - // 'client_id' => '', - // 'client_secret' => '', - // 'base_url' => 'https://dev-000000.oktapreview.com/oauth2/default' - // ], - // 'github' => [ - // 'client_id' => '', - // 'client_secret' => '' - // ], - // 'facebook' => [ - // 'client_id' => '', - // 'client_secret' => '', - // 'graph_api_version' => 'v2.8', - // ], - // 'google' => [ - // 'client_id' => '', - // 'client_secret' => '', - // 'hosted_domain' => '*', - // // Uses OpenIDConnect to fetch the email instead of using the Google+ API - // // Disabling the OIDC Mode, requires you to enable the Google+ API otherwise it will fail - // 'use_oidc_mode' => true, - // ], - // 'twitter' => [ - // 'identifier' => '', - // 'secret' => '' - // ] - ] - ], -]; diff --git a/migrations/db/schemas/20180220023138_create_activity_table.php b/migrations/db/schemas/20180220023138_create_activity_table.php deleted file mode 100644 index ae602ee604..0000000000 --- a/migrations/db/schemas/20180220023138_create_activity_table.php +++ /dev/null @@ -1,82 +0,0 @@ -table('directus_activity', ['signed' => false]); - - $table->addColumn('action', 'string', [ - 'limit' => 45, - 'null' => false - ]); - - $table->addColumn('action_by', 'integer', [ - 'signed' => false, - 'null' => false, - 'default' => 0 - ]); - - $table->addColumn('action_on', 'datetime', [ - 'default' => null - ]); - - $table->addColumn('ip', 'string', [ - 'limit' => 50, - 'default' => null - ]); - - $table->addColumn('user_agent', 'string', [ - 'limit' => 255 - ]); - - $table->addColumn('collection', 'string', [ - 'limit' => 64, - 'null' => false - ]); - - $table->addColumn('item', 'string',[ - 'limit' => 255 - ]); - - $table->addColumn('edited_on', 'datetime', [ - 'null' => true, - 'default' => null - ]); - - $table->addColumn('comment', 'text', [ - 'null' => true, - 'encoding' => 'utf8mb4' - ]); - - $table->addColumn('comment_deleted_on', 'datetime', [ - 'null' => true, - 'default' => null - ]); - - $table->create(); - } -} diff --git a/migrations/db/schemas/20180220023152_create_collections_presets_table.php b/migrations/db/schemas/20180220023152_create_collections_presets_table.php deleted file mode 100644 index f4f38af82e..0000000000 --- a/migrations/db/schemas/20180220023152_create_collections_presets_table.php +++ /dev/null @@ -1,83 +0,0 @@ -table('directus_collection_presets', ['signed' => false]); - - $table->addColumn('title', 'string', [ - 'limit' => 255, - 'null' => true, - 'default' => null, - 'encoding' => 'utf8mb4' - ]); - $table->addColumn('user', 'integer', [ - 'signed' => false, - 'null' => true - ]); - $table->addColumn('role', 'integer', [ - 'signed' => false, - 'null' => true - ]); - $table->addColumn('collection', 'string', [ - 'limit' => 64, - 'null' => false - ]); - $table->addColumn('search_query', 'string', [ - 'limit' => 100, - 'null' => true, - 'default' => null - ]); - $table->addColumn('filters', 'text', [ - 'null' => true, - 'default' => null - ]); - $table->addColumn('view_type', 'string', [ - 'limit' => 100, - 'null' => false, - 'default' => 'tabular' - ]); - $table->addColumn('view_query', 'text', [ - 'null' => true, - 'default' => null - ]); - $table->addColumn('view_options', 'text', [ - 'null' => true, - 'default' => null - ]); - $table->addColumn('translation', 'text', [ - 'null' => true, - 'default' => null - ]); - $table->addIndex(['user', 'collection', 'title'], [ - 'unique' => true, - 'name' => 'idx_user_collection_title' - ]); - - $table->create(); - } -} diff --git a/migrations/db/schemas/20180220023157_create_collections_table.php b/migrations/db/schemas/20180220023157_create_collections_table.php deleted file mode 100644 index e52b33a496..0000000000 --- a/migrations/db/schemas/20180220023157_create_collections_table.php +++ /dev/null @@ -1,71 +0,0 @@ -table('directus_collections', [ - 'id' => false, - 'primary_key' => 'collection' - ]); - - $table->addColumn('collection', 'string', [ - 'limit' => 64, - 'null' => false - ]); - $table->addColumn('managed', 'boolean', [ - 'signed' => false, - 'null' => false, - 'default' => true - ]); - $table->addColumn('hidden', 'boolean', [ - 'signed' => false, - 'null' => false, - 'default' => false - ]); - $table->addColumn('single', 'boolean', [ - 'signed' => false, - 'null' => false, - 'default' => false - ]); - $table->addColumn('icon', 'string', [ - 'limit' => 30, - 'null' => true, - 'default' => null - ]); - $table->addColumn('note', 'string', [ - 'limit' => 255, - 'null' => true, - 'default' => null - ]); - $table->addColumn('translation', 'text', [ - 'null' => true, - 'default' => null - ]); - - $table->create(); - } -} diff --git a/migrations/db/schemas/20180220023202_create_fields_table.php b/migrations/db/schemas/20180220023202_create_fields_table.php deleted file mode 100644 index 73d8891ed8..0000000000 --- a/migrations/db/schemas/20180220023202_create_fields_table.php +++ /dev/null @@ -1,115 +0,0 @@ -table('directus_fields', ['signed' => false]); - - $table->addColumn('collection', 'string', [ - 'limit' => 64, - 'null' => false - ]); - $table->addColumn('field', 'string', [ - 'limit' => 64, - 'null' => false - ]); - $table->addColumn('type', 'string', [ - 'limit' => 64, - 'null' => false - ]); - $table->addColumn('interface', 'string', [ - 'limit' => 64, - 'null' => true, - 'default' => null, - ]); - $table->addColumn('options', 'text', [ - 'null' => true, - 'default' => null - ]); - $table->addColumn('locked', 'boolean', [ - 'signed' => false, - 'null' => false, - 'default' => false - ]); - $table->addColumn('validation', 'string', [ - 'limit' => 255, - 'null' => true, - 'default' => null - ]); - $table->addColumn('required', 'boolean', [ - 'signed' => false, - 'null' => false, - 'default' => false - ]); - $table->addColumn('readonly', 'boolean', [ - 'signed' => false, - 'null' => false, - 'default' => false - ]); - $table->addColumn('hidden_detail', 'boolean', [ - 'signed' => false, - 'null' => false, - 'default' => 0 - ]); - $table->addColumn('hidden_browse', 'boolean', [ - 'signed' => false, - 'null' => false, - 'default' => 0 - ]); - $table->addColumn('sort', 'integer', [ - 'signed' => false, - 'null' => true, - 'default' => null - ]); - $table->addColumn('width', 'string', [ - 'limit' => 50, - 'null' => true, - 'default' => 'full' - ]); - $table->addColumn('group', 'integer', [ - 'signed' => false, - 'null' => true, - 'default' => null - ]); - $table->addColumn('note', 'string', [ - 'limit' => 1024, - 'null' => true, - 'default' => null - ]); - $table->addColumn('translation', 'text', [ - 'null' => true, - 'default' => null - ]); - - $table->addIndex(['collection', 'field'], [ - 'unique' => true, - 'name' => 'idx_collection_field' - ]); - - $table->create(); - } -} diff --git a/migrations/db/schemas/20180220023208_create_files_table.php b/migrations/db/schemas/20180220023208_create_files_table.php deleted file mode 100644 index 363ff572db..0000000000 --- a/migrations/db/schemas/20180220023208_create_files_table.php +++ /dev/null @@ -1,121 +0,0 @@ -table('directus_files', ['signed' => false]); - - $table->addColumn('storage', 'string', [ - 'limit' => 50, - 'null' => false, - 'default' => 'local' - ]); - $table->addColumn('filename', 'string', [ - 'limit' => 255, - 'null' => false, - 'default' => null - ]); - $table->addColumn('title', 'string', [ - 'limit' => 255, - 'null' => true, - 'default' => null - ]); - $table->addColumn('type', 'string', [ - 'limit' => 255, - 'null' => true, - 'default' => null // unknown type? - ]); - $table->addColumn('uploaded_by', 'integer', [ - 'signed' => false, - 'null' => false - ]); - // TODO: Make directus set this value to whatever default is on the server (UTC) - // In MySQL 5.5 and below doesn't support CURRENT TIMESTAMP on datetime as default - $table->addColumn('uploaded_on', 'datetime', [ - 'null' => false - ]); - $table->addColumn('charset', 'string', [ - 'limit' => 50, - 'null' => true, - 'default' => null - ]); - $table->addColumn('filesize', 'integer', [ - 'signed' => false, - 'default' => 0 - ]); - $table->addColumn('width', 'integer', [ - 'signed' => false, - 'null' => true, - 'default' => null - ]); - $table->addColumn('height', 'integer', [ - 'signed' => false, - 'null' => true, - 'default' => null - ]); - $table->addColumn('duration', 'integer', [ - 'signed' => true, - 'null' => true, - 'default' => null - ]); - $table->addColumn('embed', 'string', [ - 'limit' => 200, - 'null' => true, - 'default' => NULL - ]); - $table->addColumn('folder', 'integer', [ - 'signed' => false, - 'null' => true, - 'default' => null - ]); - $table->addColumn('description', 'text', [ - 'null' => true, - 'default' => null - ]); - $table->addColumn('location', 'string', [ - 'limit' => 200, - 'null' => true, - 'default' => null - ]); - $table->addColumn('tags', 'string', [ - 'limit' => 255, - 'null' => true, - 'default' => null - ]); - $table->addColumn('checksum', 'string', [ - 'limit' => 32, - 'null' => true, - 'default' => null - ]); - $table->addColumn('metadata', 'text', [ - 'null' => true, - 'default' => null - ]); - - $table->create(); - } -} diff --git a/migrations/db/schemas/20180220023213_create_folders_table.php b/migrations/db/schemas/20180220023213_create_folders_table.php deleted file mode 100644 index cb0596414d..0000000000 --- a/migrations/db/schemas/20180220023213_create_folders_table.php +++ /dev/null @@ -1,50 +0,0 @@ -table('directus_folders', ['signed' => false]); - - $table->addColumn('name', 'string', [ - 'limit' => 191, - 'null' => false, - 'encoding' => 'utf8mb4' - ]); - $table->addColumn('parent_folder', 'integer', [ - 'signed' => false, - 'null' => true, - 'default' => null - ]); - - $table->addIndex(['name', 'parent_folder'], [ - 'unique' => true, - 'name' => 'idx_name_parent_folder' - ]); - - $table->create(); - } -} diff --git a/migrations/db/schemas/20180220023217_create_roles_table.php b/migrations/db/schemas/20180220023217_create_roles_table.php deleted file mode 100644 index 2f07fe0110..0000000000 --- a/migrations/db/schemas/20180220023217_create_roles_table.php +++ /dev/null @@ -1,75 +0,0 @@ -table('directus_roles', ['signed' => false]); - - $table->addColumn('name', 'string', [ - 'limit' => 100, - 'null' => false - ]); - $table->addColumn('description', 'string', [ - 'limit' => 500, - 'null' => true, - 'default' => NULL - ]); - $table->addColumn('ip_whitelist', 'text', [ - 'null' => true, - 'default' => null - ]); - $table->addColumn('nav_blacklist', 'text', [ - 'null' => true, - 'default' => null - ]); - $table->addColumn('external_id', 'string', [ - 'limit' => 255, - 'null' => true, - 'default' => null - ]); - $table->addColumn('nav_override', 'text', [ - 'null' => true, - 'default' => null - ]); - $table->addColumn('enforce_2fa', 'boolean', [ - 'null' => true, - 'default' => false - ]); - - $table->addIndex('name', [ - 'unique' => true, - 'name' => 'idx_group_name' - ]); - - $table->addIndex('external_id', [ - 'unique' => true, - 'name' => 'idx_roles_external_id' - ]); - - $table->create(); - } -} diff --git a/migrations/db/schemas/20180220023226_create_permissions_table.php b/migrations/db/schemas/20180220023226_create_permissions_table.php deleted file mode 100644 index 47caedc97d..0000000000 --- a/migrations/db/schemas/20180220023226_create_permissions_table.php +++ /dev/null @@ -1,99 +0,0 @@ -table('directus_permissions', ['signed' => false]); - - $table->addColumn('collection', 'string', [ - 'limit' => 64, - 'null' => false, - ]); - $table->addColumn('role', 'integer', [ - 'signed' => false, - 'null' => false - ]); - $table->addColumn('status', 'string', [ - 'length' => 64, - 'default' => null, - 'null' => true - ]); - $table->addColumn('create', 'string', [ - 'signed' => false, - 'null' => true, - 'default' => 'none', - 'length' => 16, - ]); - $table->addColumn('read', 'string', [ - 'signed' => false, - 'null' => true, - 'default' => 'none', - 'length' => 16, - ]); - $table->addColumn('update', 'string', [ - 'signed' => false, - 'null' => true, - 'default' => 'none', - 'length' => 16, - ]); - $table->addColumn('delete', 'string', [ - 'signed' => false, - 'null' => true, - 'default' => 'none', - 'length' => 16, - ]); - $table->addColumn('comment', 'string', [ - 'limit' => 8, - 'null' => true, - 'default' => 'none' - ]); - $table->addColumn('explain', 'string', [ - 'limit' => 8, - 'null' => true, - 'default' => 'none' - ]); - $table->addColumn('read_field_blacklist', 'string', [ - 'limit' => 1000, - 'null' => true, - 'default' => null, - 'encoding' => 'utf8' - ]); - $table->addColumn('write_field_blacklist', 'string', [ - 'limit' => 1000, - 'null' => true, - 'default' => NULL, - 'encoding' => 'utf8', - ]); - $table->addColumn('status_blacklist', 'string', [ - 'length' => 1000, - 'default' => null, - 'null' => true - ]); - - $table->create(); - } -} diff --git a/migrations/db/schemas/20180220023232_create_relations_table.php b/migrations/db/schemas/20180220023232_create_relations_table.php deleted file mode 100644 index 7a2408abd8..0000000000 --- a/migrations/db/schemas/20180220023232_create_relations_table.php +++ /dev/null @@ -1,55 +0,0 @@ -table('directus_relations', ['signed' => false]); - - $table->addColumn('collection_many', 'string', [ - 'limit' => 64, - 'null' => false - ]); - $table->addColumn('field_many', 'string', [ - 'limit' => 45, - 'null' => false - ]); - $table->addColumn('collection_one', 'string', [ - 'limit' => 64, - 'null' => true - ]); - $table->addColumn('field_one', 'string', [ - 'limit' => 64, - 'null' => true - ]); - $table->addColumn('junction_field', 'string', [ - 'limit' => 64, - 'null' => true - ]); - - $table->create(); - } -} diff --git a/migrations/db/schemas/20180220023238_create_revisions_table.php b/migrations/db/schemas/20180220023238_create_revisions_table.php deleted file mode 100644 index fe7f729bb1..0000000000 --- a/migrations/db/schemas/20180220023238_create_revisions_table.php +++ /dev/null @@ -1,66 +0,0 @@ -table('directus_revisions', ['signed' => false]); - - $table->addColumn('activity', 'integer', [ - 'null' => false, - 'signed' => false - ]); - $table->addColumn('collection', 'string', [ - 'limit' => 64, - 'null' => false - ]); - $table->addColumn('item', 'string', [ - 'limit' => 255 - ]); - $table->addColumn('data', 'text', [ - 'limit' => 4294967295 - ]); - $table->addColumn('delta', 'text', [ - 'limit' => 4294967295, - 'null' => true - ]); - $table->addColumn('parent_collection', 'string', [ - 'limit' => 64, - 'null' => true - ]); - $table->addColumn('parent_item', 'string', [ - 'limit' => 255, - 'null' => true - ]); - $table->addColumn('parent_changed', 'boolean', [ - 'signed' => false, - 'default' => false, - 'null' => true - ]); - - $table->create(); - } -} diff --git a/migrations/db/schemas/20180220023243_create_settings_table.php b/migrations/db/schemas/20180220023243_create_settings_table.php deleted file mode 100644 index b2ca880b49..0000000000 --- a/migrations/db/schemas/20180220023243_create_settings_table.php +++ /dev/null @@ -1,47 +0,0 @@ -table('directus_settings', ['signed' => false]); - - $table->addColumn('key', 'string', [ - 'limit' => 64, - 'null' => false - ]); - $table->addColumn('value', 'text', [ - 'default' => null - ]); - - $table->addIndex(['key'], [ - 'unique' => true, - 'name' => 'idx_key' - ]); - - $table->create(); - } -} diff --git a/migrations/db/schemas/20180220023248_create_users_table.php b/migrations/db/schemas/20180220023248_create_users_table.php deleted file mode 100644 index 9aa70d77b4..0000000000 --- a/migrations/db/schemas/20180220023248_create_users_table.php +++ /dev/null @@ -1,143 +0,0 @@ -table('directus_users', ['signed' => false]); - - $table->addColumn('status', 'string', [ - 'limit' => 16, - 'default' => \Directus\Database\TableGateway\DirectusUsersTableGateway::STATUS_DRAFT - ]); - $table->addColumn('role', 'integer', [ - 'null' => true, - 'default' => null - ]); - $table->addColumn('first_name', 'string', [ - 'limit' => 50, - 'null' => true, - 'default' => null - ]); - $table->addColumn('last_name', 'string', [ - 'limit' => 50, - 'null' => true, - 'default' => null - ]); - $table->addColumn('email', 'string', [ - 'limit' => 128, - 'null' => false - ]); - $table->addColumn('password', 'string', [ - 'limit' => 255, - 'encoding' => 'utf8', - 'null' => true, - 'default' => null - ]); - $table->addColumn('token', 'string', [ - 'limit' => 255, - 'encoding' => 'utf8', - 'null' => true, - 'default' => null - ]); - $table->addColumn('timezone', 'string', [ - 'limit' => 32, - 'default' => date_default_timezone_get(), - ]); - $table->addColumn('locale', 'string', [ - 'limit' => 8, - 'null' => true, - 'default' => null - ]); - $table->addColumn('locale_options', 'text', [ - 'null' => true, - 'default' => null - ]); - $table->addColumn('avatar', 'integer', [ - 'signed' => false, - 'limit' => 11, - 'null' => true, - 'default' => null - ]); - $table->addColumn('company', 'string', [ - 'limit' => 191, - 'null' => true, - 'default' => null - ]); - $table->addColumn('title', 'string', [ - 'limit' => 191, - 'null' => true, - 'default' => null - ]); - $table->addColumn('email_notifications', 'integer', [ - 'limit' => 1, - 'default' => 1 - ]); - $table->addColumn('last_access_on', 'datetime', [ - 'null' => true, - 'default' => null - ]); - $table->addColumn('last_page', 'string', [ - 'limit' => 192, - 'null' => true, - 'default' => null - ]); - $table->addColumn('external_id', 'string', [ - 'limit' => 255, - 'null' => true, - 'default' => null - ]); - $table->addColumn('theme', 'string', [ - 'limit' => 100, - 'encoding' => 'utf8', - 'null' => true, - 'default' => 'auto' - ]); - $table->addColumn('2fa_secret', 'string', [ - 'limit' => 100, - 'encoding' => 'utf8', - 'null' => true, - 'default' => null - ]); - - $table->addIndex('email', [ - 'unique' => true, - 'name' => 'idx_users_email' - ]); - - $table->addIndex('token', [ - 'unique' => true, - 'name' => 'idx_users_token' - ]); - - $table->addIndex('external_id', [ - 'unique' => true, - 'name' => 'idx_users_external_id' - ]); - - $table->create(); - } -} diff --git a/migrations/db/schemas/20190912072543_create_user_sessions.php b/migrations/db/schemas/20190912072543_create_user_sessions.php deleted file mode 100644 index 72aec69d50..0000000000 --- a/migrations/db/schemas/20190912072543_create_user_sessions.php +++ /dev/null @@ -1,76 +0,0 @@ -table('directus_user_sessions', ['signed' => false]); - - $table->addColumn('user', 'integer', [ - 'signed' => false, - 'null' => true, - 'default' => null - ]); - - $table->addColumn('token_type', 'string', [ - 'null' => true, - 'default' => null - ]); - - $table->addColumn('token', 'string', [ - 'limit' => 520, - 'encoding' => 'utf8', - 'null' => true, - 'default' => null - ]); - - $table->addColumn('ip_address', 'string', [ - 'limit' => 255, - 'encoding' => 'utf8', - 'null' => true, - 'default' => null - ]); - - $table->addColumn('user_agent', 'text', [ - 'default' => null, - 'null' => true, - 'default' => null - ]); - - $table->addColumn('created_on', 'datetime', [ - 'null' => true, - 'default' => null - ]); - - $table->addColumn('token_expired_at', 'datetime', [ - 'null' => true, - 'default' => null - ]); - - $table->create(); - } -} diff --git a/migrations/db/schemas/20190917090849_create_web_hooks.php b/migrations/db/schemas/20190917090849_create_web_hooks.php deleted file mode 100644 index 1be2ad47a3..0000000000 --- a/migrations/db/schemas/20190917090849_create_web_hooks.php +++ /dev/null @@ -1,68 +0,0 @@ -table('directus_webhooks', ['signed' => false]); - - $table->addColumn('status', 'string', [ - 'limit' => 16, - 'default' => \Directus\Api\Routes\Webhook::STATUS_INACTIVE - ]); - - - $table->addColumn('http_action', 'string', [ - 'limit' => 255, - 'encoding' => 'utf8', - 'null' => true, - 'default' => null - ]); - - $table->addColumn('url', 'string', [ - 'limit' => 510, - 'encoding' => 'utf8', - 'null' => true, - 'default' => null - ]); - - $table->addColumn('collection', 'string', [ - 'limit' => 255, - 'null' => true, - 'default' => null - ]); - - $table->addColumn('directus_action', 'string', [ - 'limit' => 255, - 'encoding' => 'utf8', - 'null' => true, - 'default' => null - ]); - - $table->create(); - } -} diff --git a/migrations/db/seeds/CollectionPresetsSeeder.php b/migrations/db/seeds/CollectionPresetsSeeder.php deleted file mode 100644 index 65fae06913..0000000000 --- a/migrations/db/seeds/CollectionPresetsSeeder.php +++ /dev/null @@ -1,85 +0,0 @@ - 'directus_activity', - 'view_type' => 'timeline', - 'view_query' => json_encode([ - 'timeline' => [ - 'sort' => '-action_on' - ] - ]), - 'view_options' => json_encode([ - 'timeline' => [ - 'date' => 'action_on', - 'title' => '{{ action_by.first_name }} {{ action_by.last_name }} ({{ action }})', - 'content' => 'action_by', - 'color' => 'action' - ] - ]) - ], - [ - 'collection' => 'directus_files', - 'view_type' => 'cards', - 'view_options' => json_encode([ - 'cards' => [ - 'title' => 'title', - 'subtitle' => 'type', - 'content' => 'description', - 'src' => 'data' - ] - ]) - ], - [ - 'collection' => 'directus_users', - 'view_type' => 'cards', - 'view_options' => json_encode([ - 'cards' => [ - 'title' => 'first_name', - 'subtitle' => 'last_name', - 'content' => 'title', - 'src' => 'avatar', - 'icon' => 'person' - ] - ]) - ], - [ - 'collection' => 'directus_webhooks', - 'view_type' => 'tabular', - 'view_query' => json_encode([ - 'tabular' => [ - 'fields' => 'status,http_action,url,collection,directus_action' - ] - ]), - 'view_options' => json_encode([ - 'tabular' => [ - 'widths' => [ - 'status' => 32, - 'http_action' => 72, - 'url' => 200, - 'collection' => 200, - 'directus_action' => 200 - ] - ] - ]) - ] - ]; - - $files = $this->table('directus_collection_presets'); - $files->insert($data)->save(); - } -} diff --git a/migrations/db/seeds/FieldsSeeder.php b/migrations/db/seeds/FieldsSeeder.php deleted file mode 100644 index 59d6045bc4..0000000000 --- a/migrations/db/seeds/FieldsSeeder.php +++ /dev/null @@ -1,1915 +0,0 @@ - 'directus_activity', - 'field' => 'id', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'primary-key', - 'locked' => 1, - 'readonly' => 1, - 'required' => 1, - 'hidden_detail' => 1 - ], - [ - 'collection' => 'directus_activity', - 'field' => 'action', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'activity-icon', - 'options' => json_encode([ - 'iconRight' => 'change_history' - ]), - 'locked' => 1, - 'readonly' => 1, - 'sort' => 1, - 'width' => 'full' - ], - [ - 'collection' => 'directus_activity', - 'field' => 'collection', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'collections', - 'options' => json_encode([ - 'iconRight' => 'list_alt' - ]), - 'locked' => 1, - 'readonly' => 1, - 'sort' => 2, - 'width' => 'half' - ], - [ - 'collection' => 'directus_activity', - 'field' => 'item', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'options' => json_encode([ - 'iconRight' => 'link' - ]), - 'locked' => 1, - 'readonly' => 1, - 'sort' => 3, - 'width' => 'half' - ], - [ - 'collection' => 'directus_activity', - 'field' => 'action_by', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'user', - 'options' => json_encode([ - 'iconRight' => 'account_circle' - ]), - 'locked' => 1, - 'readonly' => 1, - 'sort' => 4, - 'width' => 'half' - ], - [ - 'collection' => 'directus_activity', - 'field' => 'action_on', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_DATETIME, - 'interface' => 'datetime', - 'options' => json_encode([ - 'showRelative' => true, - 'iconRight' => 'calendar_today' - ]), - 'locked' => 1, - 'readonly' => 1, - 'sort' => 5, - 'width' => 'half' - ], - [ - 'collection' => 'directus_activity', - 'field' => 'edited_on', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_DATETIME, - 'interface' => 'datetime', - 'options' => json_encode([ - 'showRelative' => true, - 'iconRight' => 'edit' - ]), - 'locked' => 1, - 'readonly' => 1, - 'sort' => 6, - 'width' => 'half' - ], - [ - 'collection' => 'directus_activity', - 'field' => 'comment_deleted_on', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_DATETIME, - 'interface' => 'datetime', - 'options' => json_encode([ - 'showRelative' => true, - 'iconRight' => 'delete_outline' - ]), - 'locked' => 1, - 'readonly' => 1, - 'sort' => 7, - 'width' => 'half' - ], - [ - 'collection' => 'directus_activity', - 'field' => 'ip', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'options' => json_encode([ - 'iconRight' => 'my_location' - ]), - 'locked' => 1, - 'readonly' => 1, - 'sort' => 8, - 'width' => 'half' - ], - [ - 'collection' => 'directus_activity', - 'field' => 'user_agent', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'options' => json_encode([ - 'iconRight' => 'devices_other' - ]), - 'locked' => 1, - 'readonly' => 1, - 'sort' => 9, - 'width' => 'half' - ], - [ - 'collection' => 'directus_activity', - 'field' => 'comment', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'textarea', - 'locked' => 1, - 'readonly' => 1, - 'sort' => 10, - 'width' => 'full' - ], - - - // Collection Presets - // ----------------------------------------------------------------- - [ - 'collection' => 'directus_collection_presets', - 'field' => 'id', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'primary-key', - 'locked' => 1 - ], - [ - 'collection' => 'directus_collection_presets', - 'field' => 'title', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1 - ], - [ - 'collection' => 'directus_collection_presets', - 'field' => 'user', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'user', - 'locked' => 1 - ], - [ - 'collection' => 'directus_collection_presets', - 'field' => 'role', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, - 'interface' => 'many-to-one', - 'locked' => 1 - ], - [ - 'collection' => 'directus_collection_presets', - 'field' => 'collection', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, - 'interface' => 'many-to-one', - 'locked' => 1 - ], - [ - 'collection' => 'directus_collection_presets', - 'field' => 'search_query', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1 - ], - [ - 'collection' => 'directus_collection_presets', - 'field' => 'filters', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, - 'interface' => 'json', - 'locked' => 1 - ], - [ - 'collection' => 'directus_collection_presets', - 'field' => 'view_options', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, - 'interface' => 'json', - 'locked' => 1 - ], - [ - 'collection' => 'directus_collection_presets', - 'field' => 'view_type', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1 - ], - [ - 'collection' => 'directus_collection_presets', - 'field' => 'view_query', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, - 'interface' => 'json', - 'locked' => 1 - ], - - // Collections - // ----------------------------------------------------------------- - [ - 'collection' => 'directus_collections', - 'field' => 'fields', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_O2M, - 'interface' => 'one-to-many', - 'locked' => 1, - 'hidden_detail' => 1, - 'hidden_browse' => 1, - 'sort' => 1 - ], - [ - 'collection' => 'directus_collections', - 'field' => 'collection', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'primary-key', - 'locked' => 1, - 'readonly' => 1, - 'required' => 1, - 'sort' => 2, - 'width' => 'half' - ], - [ - 'collection' => 'directus_collections', - 'field' => 'note', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1, - 'sort' => 3, - 'width' => 'half', - 'note' => 'An internal description.' - ], - [ - 'collection' => 'directus_collections', - 'field' => 'managed', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, - 'interface' => 'toggle', - 'locked' => 1, - 'sort' => 4, - 'width' => 'half', - 'hidden_detail' => 1, - 'note' => '[Learn More](https://docs.directus.io/guides/collections.html#managing-collections).' - ], - [ - 'collection' => 'directus_collections', - 'field' => 'hidden', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, - 'interface' => 'toggle', - 'locked' => 1, - 'sort' => 5, - 'width' => 'half', - 'note' => '[Learn More](https://docs.directus.io/guides/collections.html#hidden).' - ], - [ - 'collection' => 'directus_collections', - 'field' => 'single', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, - 'interface' => 'toggle', - 'locked' => 1, - 'sort' => 6, - 'width' => 'half', - 'note' => '[Learn More](https://docs.directus.io/guides/collections.html#single).' - ], - [ - 'collection' => 'directus_collections', - 'field' => 'translation', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, - 'interface' => 'json', - 'locked' => 1, - 'sort' => 7, - 'hidden_detail' => 1 - ], - [ - 'collection' => 'directus_collections', - 'field' => 'icon', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'icon', - 'locked' => 1, - 'sort' => 8, - 'note' => 'The icon shown in the App\'s navigation sidebar.' - ], - - - // Fields - // ----------------------------------------------------------------- - [ - 'collection' => 'directus_fields', - 'field' => 'id', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'primary-key', - 'locked' => 1, - 'required' => 1, - 'hidden_detail' => 1 - ], - [ - 'collection' => 'directus_fields', - 'field' => 'collection', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, - 'interface' => 'many-to-one', - 'locked' => 1 - ], - [ - 'collection' => 'directus_fields', - 'field' => 'field', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1 - ], - [ - 'collection' => 'directus_fields', - 'field' => 'type', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'primary-key', - 'locked' => 1 - ], - [ - 'collection' => 'directus_fields', - 'field' => 'interface', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'primary-key', - 'locked' => 1 - ], - [ - 'collection' => 'directus_fields', - 'field' => 'options', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, - 'interface' => 'json', - 'locked' => 1 - ], - [ - 'collection' => 'directus_fields', - 'field' => 'locked', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, - 'interface' => 'toggle', - 'locked' => 1 - ], - [ - 'collection' => 'directus_fields', - 'field' => 'translation', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, - 'interface' => 'json', - 'locked' => 1 - ], - [ - 'collection' => 'directus_fields', - 'field' => 'readonly', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, - 'interface' => 'toggle', - 'locked' => 1 - ], - [ - 'collection' => 'directus_fields', - 'field' => 'validation', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1, - ], - [ - 'collection' => 'directus_fields', - 'field' => 'required', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, - 'interface' => 'toggle', - 'locked' => 1 - ], - [ - 'collection' => 'directus_fields', - 'field' => 'sort', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_SORT, - 'interface' => 'sort', - 'locked' => 1 - ], - [ - 'collection' => 'directus_fields', - 'field' => 'note', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1 - ], - [ - 'collection' => 'directus_fields', - 'field' => 'hidden_detail', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, - 'interface' => 'toggle', - 'locked' => 1 - ], - [ - 'collection' => 'directus_fields', - 'field' => 'hidden_browse', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, - 'interface' => 'toggle', - 'locked' => 1 - ], - [ - 'collection' => 'directus_fields', - 'field' => 'width', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'numeric', - 'locked' => 1 - ], - [ - 'collection' => 'directus_fields', - 'field' => 'group', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, - 'interface' => 'many-to-one', - 'locked' => 1 - ], - - - // Files - // ----------------------------------------------------------------- - [ - 'collection' => 'directus_files', - 'field' => 'data', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_ALIAS, - 'interface' => 'file', - 'locked' => 1, - 'hidden_detail' => 1 - ], - [ - 'collection' => 'directus_files', - 'field' => 'id', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'primary-key', - 'locked' => 1, - 'required' => 1, - 'hidden_detail' => 1 - ], - [ - 'collection' => 'directus_files', - 'field' => 'preview', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_ALIAS, - 'interface' => 'file-preview', - 'locked' => 1, - 'sort' => 1, - 'width' => 'full' - ], - [ - 'collection' => 'directus_files', - 'field' => 'title', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'options' => json_encode([ - 'placeholder' => 'Enter a descriptive title...', - 'iconRight' => 'title' - ]), - 'locked' => 1, - 'sort' => 3, - 'width' => 'half' - ], - [ - 'collection' => 'directus_files', - 'field' => 'filename', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'options' => json_encode([ - 'placeholder' => 'Enter a unique file name...', - 'iconRight' => 'insert_drive_file' - ]), - 'locked' => 1, - 'readonly' => 1, - 'sort' => 4, - 'width' => 'half', - 'required' => 1 - ], - [ - 'collection' => 'directus_files', - 'field' => 'tags', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_ARRAY, - 'interface' => 'tags', - 'options' => json_encode([ - 'placeholder' => 'Enter a keyword then hit enter...' - ]), - 'sort' => 5, - 'width' => 'half' - ], - [ - 'collection' => 'directus_files', - 'field' => 'location', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'options' => json_encode([ - 'placeholder' => 'Enter a location...', - 'iconRight' => 'place' - ]), - 'sort' => 6, - 'width' => 'half' - ], - [ - 'collection' => 'directus_files', - 'field' => 'description', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'wysiwyg', - 'options' => json_encode([ - 'toolbar' => ['bold','italic','underline','link','code'] - ]), - 'sort' => 7, - 'width' => 'full' - ], - [ - 'collection' => 'directus_files', - 'field' => 'uploaded_on', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_DATETIME, - 'interface' => 'datetime', - 'options' => json_encode([ - 'iconRight' => 'today' - ]), - 'locked' => 1, - 'readonly' => 1, - 'sort' => 8, - 'width' => 'half', - 'required' => 1 - ], - [ - 'collection' => 'directus_files', - 'field' => 'uploaded_by', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_USER_CREATED, - 'interface' => 'user-created', - 'locked' => 1, - 'readonly' => 1, - 'sort' => 9, - 'width' => 'half', - 'required' => 1 - ], - [ - 'collection' => 'directus_files', - 'field' => 'width', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'numeric', - 'options' => json_encode([ - 'iconRight' => 'straighten' - ]), - 'locked' => 1, - 'readonly' => 1, - 'sort' => 10, - 'width' => 'half' - ], - [ - 'collection' => 'directus_files', - 'field' => 'height', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'numeric', - 'options' => json_encode([ - 'iconRight' => 'straighten' - ]), - 'locked' => 1, - 'readonly' => 1, - 'sort' => 11, - 'width' => 'half' - ], - [ - 'collection' => 'directus_files', - 'field' => 'duration', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'numeric', - 'options' => json_encode([ - 'iconRight' => 'timer' - ]), - 'locked' => 1, - 'readonly' => 1, - 'sort' => 12, - 'width' => 'half' - ], - [ - 'collection' => 'directus_files', - 'field' => 'filesize', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'file-size', - 'options' => json_encode([ - 'iconRight' => 'storage' - ]), - 'locked' => 1, - 'readonly' => 1, - 'sort' => 13, - 'width' => 'half' - ], - [ - 'collection' => 'directus_files', - 'field' => 'metadata', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, - 'interface' => 'json', - 'locked' => 1, - 'sort' => 14, - 'width' => 'full' - ], - [ - 'collection' => 'directus_files', - 'field' => 'type', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1, - 'readonly' => 1, - 'hidden_detail' => 1 - ], - [ - 'collection' => 'directus_files', - 'field' => 'charset', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1, - 'readonly' => 1, - 'hidden_detail' => 1, - 'hidden_browse' => 1 - ], - [ - 'collection' => 'directus_files', - 'field' => 'embed', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1, - 'readonly' => 1, - 'hidden_detail' => 1 - ], - [ - 'collection' => 'directus_files', - 'field' => 'folder', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, - 'interface' => 'many-to-one', - 'locked' => 1, - 'hidden_detail' => 1 - ], - [ - 'collection' => 'directus_files', - 'field' => 'storage', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1, - 'hidden_detail' => 1, - 'hidden_browse' => 1 - ], - [ - 'collection' => 'directus_files', - 'field' => 'checksum', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1, - 'readonly' => 1, - 'hidden_detail' => 1, - 'hidden_browse' => 1 - ], - - - // Folders - // ----------------------------------------------------------------- - [ - 'collection' => 'directus_folders', - 'field' => 'id', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'primary-key', - 'locked' => 1, - 'required' => 1, - 'hidden_detail' => 1 - ], - [ - 'collection' => 'directus_folders', - 'field' => 'name', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1 - ], - [ - 'collection' => 'directus_folders', - 'field' => 'parent_folder', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, - 'interface' => 'many-to-one', - 'locked' => 1 - ], - - - // Permissions - // ----------------------------------------------------------------- - [ - 'collection' => 'directus_permissions', - 'field' => 'id', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'primary-key', - 'locked' => 1, - 'required' => 1, - 'hidden_detail' => 1 - ], - [ - 'collection' => 'directus_permissions', - 'field' => 'collection', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, - 'interface' => 'many-to-one', - 'locked' => 1 - ], - [ - 'collection' => 'directus_permissions', - 'field' => 'role', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, - 'interface' => 'many-to-one', - 'locked' => 1 - ], - [ - 'collection' => 'directus_permissions', - 'field' => 'status', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1 - ], - [ - 'collection' => 'directus_permissions', - 'field' => 'create', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1 - ], - [ - 'collection' => 'directus_permissions', - 'field' => 'read', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1 - ], - [ - 'collection' => 'directus_permissions', - 'field' => 'update', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1 - ], - [ - 'collection' => 'directus_permissions', - 'field' => 'delete', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'primary-key', - 'locked' => 1 - ], - [ - 'collection' => 'directus_permissions', - 'field' => 'comment', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1 - ], - [ - 'collection' => 'directus_permissions', - 'field' => 'explain', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1 - ], - [ - 'collection' => 'directus_permissions', - 'field' => 'status_blacklist', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_ARRAY, - 'interface' => 'tags', - 'locked' => 1 - ], - [ - 'collection' => 'directus_permissions', - 'field' => 'read_field_blacklist', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_ARRAY, - 'interface' => 'tags', - 'locked' => 1 - ], - [ - 'collection' => 'directus_permissions', - 'field' => 'write_field_blacklist', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_ARRAY, - 'interface' => 'tags', - 'locked' => 1 - ], - - - // Relations - // ----------------------------------------------------------------- - [ - 'collection' => 'directus_relations', - 'field' => 'id', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'primary-key', - 'locked' => 1 - ], - [ - 'collection' => 'directus_relations', - 'field' => 'collection_many', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'collections', - 'locked' => 1 - ], - [ - 'collection' => 'directus_relations', - 'field' => 'field_many', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1 - ], - [ - 'collection' => 'directus_relations', - 'field' => 'collection_one', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'collections', - 'locked' => 1 - ], - [ - 'collection' => 'directus_relations', - 'field' => 'field_one', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1 - ], - [ - 'collection' => 'directus_relations', - 'field' => 'junction_field', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1 - ], - - - // Revisions - // ----------------------------------------------------------------- - [ - 'collection' => 'directus_revisions', - 'field' => 'id', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'primary-key', - 'locked' => 1 - ], - [ - 'collection' => 'directus_revisions', - 'field' => 'activity', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, - 'interface' => 'many-to-one', - 'locked' => 1 - ], - [ - 'collection' => 'directus_revisions', - 'field' => 'collection', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, - 'interface' => 'many-to-one', - 'locked' => 1 - ], - [ - 'collection' => 'directus_revisions', - 'field' => 'item', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1 - ], - [ - 'collection' => 'directus_revisions', - 'field' => 'data', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, - 'interface' => 'json', - 'locked' => 1 - ], - [ - 'collection' => 'directus_revisions', - 'field' => 'delta', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, - 'interface' => 'json', - 'locked' => 1 - ], - [ - 'collection' => 'directus_revisions', - 'field' => 'parent_item', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1 - ], - [ - 'collection' => 'directus_revisions', - 'field' => 'parent_collection', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'collections', - 'locked' => 1 - ], - [ - 'collection' => 'directus_revisions', - 'field' => 'parent_changed', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, - 'interface' => 'toggle', - 'locked' => 1 - ], - - - // Roles - // ----------------------------------------------------------------- - [ - 'collection' => 'directus_roles', - 'field' => 'id', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'primary-key', - 'locked' => 1, - 'required' => 1, - 'hidden_detail' => 1 - ], - [ - 'collection' => 'directus_roles', - 'field' => 'external_id', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1, - 'readonly' => 1, - 'hidden_detail' => 1, - 'hidden_browse' => 1 - ], - [ - 'collection' => 'directus_roles', - 'field' => 'name', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1, - 'sort' => 1, - 'width' => 'half', - 'required' => 1 - ], - [ - 'collection' => 'directus_roles', - 'field' => 'description', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1, - 'sort' => 2, - 'width' => 'half' - ], - [ - 'collection' => 'directus_roles', - 'field' => 'ip_whitelist', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'textarea', - 'locked' => 1 - ], - [ - 'collection' => 'directus_roles', - 'field' => 'nav_blacklist', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'textarea', - 'locked' => 1, - 'hidden_detail' => 1, - 'hidden_browse' => 1 - ], - [ - 'collection' => 'directus_roles', - 'field' => 'users', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_O2M, - 'interface' => 'one-to-many', - 'locked' => 1, - 'options' => json_encode([ - 'fields' => "first_name,last_name" - ]) - ], - [ - 'collection' => 'directus_roles', - 'field' => 'nav_override', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, - 'interface' => 'json', - 'locked' => 1, - 'options' => '[ - { - "title": "$t:collections", - "include": "collections" - }, - { - "title": "$t:bookmarks", - "include": "bookmarks" - }, - { - "title": "$t:extensions", - "include": "extensions" - }, - { - "title": "Custom Links", - "links": [ - { - "name": "RANGER Studio", - "path": "https://rangerstudio.com", - "icon": "star" - }, - { - "name": "Movies", - "path": "/collections/movies" - } - ] - } - ]' - ], - - // Settings - // ----------------------------------------------------------------- - [ - 'collection' => 'directus_settings', - 'field' => 'project_name', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'options' => json_encode([ - 'iconRight' => 'title' - ]), - 'locked' => 1, - 'required' => 1, - 'width' => 'half', - 'note' => 'Logo in the top-left of the App (40x40)', - 'sort' => 1 - ], - [ - 'collection' => 'directus_settings', - 'field' => 'project_url', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'options' => json_encode([ - 'iconRight' => 'link' - ]), - 'locked' => 1, - 'width' => 'half', - 'note' => 'External link for the App\'s top-left logo', - 'sort' => 2 - ], - [ - 'collection' => 'directus_settings', - 'field' => 'project_logo', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_FILE, - 'interface' => 'file', - 'locked' => 1, - 'width' => 'half', - 'note' => 'A 40x40 brand logo, ideally a white SVG/PNG', - 'sort' => 3 - ], - [ - 'collection' => 'directus_settings', - 'field' => 'project_color', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'color-palette', - 'locked' => 1, - 'width' => 'half', - 'note' => 'Color for login background and App\'s logo', - 'sort' => 4 - ], - [ - 'collection' => 'directus_settings', - 'field' => 'project_foreground', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_FILE, - 'interface' => 'file', - 'locked' => 1, - 'width' => 'half', - 'note' => 'Centered image (eg: logo) for the login page', - 'sort' => 5 - ], - [ - 'collection' => 'directus_settings', - 'field' => 'project_background', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_FILE, - 'interface' => 'file', - 'locked' => 1, - 'width' => 'half', - 'note' => 'Full-screen background for the login page', - 'sort' => 6 - ], - [ - 'collection' => 'directus_settings', - 'field' => 'default_locale', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'language', - 'locked' => 1, - 'width' => 'half', - 'note' => 'Default locale for Directus Users', - 'sort' => 7, - 'options' => json_encode([ - 'limit' => true - ]) - ], - [ - 'collection' => 'directus_settings', - 'field' => 'telemetry', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, - 'interface' => 'toggle', - 'locked' => 1, - 'width' => 'half', - 'note' => 'Learn More', - 'sort' => 8 - ], - [ - 'collection' => 'directus_settings', - 'field' => 'data_divider', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_ALIAS, - 'interface' => 'divider', - 'options' => json_encode([ - 'style' => 'large', - 'title' => 'Data', - 'hr' => true - ]), - 'locked' => 1, - 'width' => 'full', - 'hidden_browse' => 1, - 'sort' => 10 - ], - [ - 'collection' => 'directus_settings', - 'field' => 'default_limit', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'numeric', - 'options' => json_encode([ - 'iconRight' => 'keyboard_tab' - ]), - 'locked' => 1, - 'required' => 1, - 'width' => 'half', - 'note' => 'Default item count in API and App responses', - 'sort' => 11 - ], - [ - 'collection' => 'directus_settings', - 'field' => 'sort_null_last', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, - 'interface' => 'toggle', - 'locked' => 1, - 'note' => 'NULL values are sorted last', - 'width' => 'half', - 'sort' => 12 - ], - [ - 'collection' => 'directus_settings', - 'field' => 'security_divider', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_ALIAS, - 'interface' => 'divider', - 'options' => json_encode([ - 'style' => 'large', - 'title' => 'Security', - 'hr' => true - ]), - 'locked' => 1, - 'hidden_browse' => 1, - 'width' => 'full', - 'sort' => 20 - ], - [ - 'collection' => 'directus_settings', - 'field' => 'auto_sign_out', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'numeric', - 'options' => json_encode([ - 'iconRight' => 'timer' - ]), - 'locked' => 1, - 'required' => 1, - 'width' => 'half', - 'note' => 'Minutes before idle users are signed out', - 'sort' => 22 - ], - [ - 'collection' => 'directus_settings', - 'field' => 'login_attempts_allowed', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'numeric', - 'options' => json_encode([ - 'iconRight' => 'lock' - ]), - 'locked' => 1, - 'width' => 'half', - 'note' => 'Failed login attempts before suspending users', - 'sort' => 23 - ], - [ - 'collection' => 'directus_settings', - 'field' => 'files_divider', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_ALIAS, - 'interface' => 'divider', - 'options' => json_encode([ - 'style' => 'large', - 'title' => 'Files & Thumbnails', - 'hr' => true - ]), - 'locked' => 1, - 'hidden_browse' => 1, - 'width' => 'full', - 'sort' => 30 - ], - [ - 'collection' => 'directus_settings', - 'field' => 'file_naming', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'dropdown', - 'locked' => 1, - 'width' => 'half', - 'note' => 'File-system naming convention for uploads', - 'sort' => 31, - 'options' => json_encode([ - 'choices' => [ - 'uuid' => 'File Hash (Obfuscated)', - 'file_name' => 'File Name (Readable)' - ] - ]) - ], - [ - 'collection' => 'directus_settings', - 'field' => 'file_max_size', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'options' => json_encode([ - 'placeholder' => 'eg: 4MB', - 'iconRight' => 'storage' - ]), - 'locked' => 1, - 'width' => 'half', - 'sort' => 32 - ], - [ - 'collection' => 'directus_settings', - 'field' => 'file_mimetype_whitelist', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_ARRAY, - 'interface' => 'tags', - 'options' => json_encode([ - 'placeholder' => 'Enter a file mimetype then hit enter (eg: image/jpeg)' - ]), - 'locked' => 1, - 'width' => 'full', - 'sort' => 33 - ], - [ - 'collection' => 'directus_settings', - 'field' => 'thumbnail_dimensions', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_ARRAY, - 'interface' => 'tags', - 'options' => json_encode([ - 'placeholder' => 'Allowed dimensions for thumbnails (eg: 200x200)' - ]), - 'locked' => 1, - 'width' => 'full', - 'note' => 'Allowed dimensions for thumbnails.', - 'sort' => 34 - ], - [ - 'collection' => 'directus_settings', - 'field' => 'thumbnail_quality_tags', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, - 'interface' => 'json', - 'locked' => 1, - 'width' => 'half', - 'note' => 'Allowed qualities for thumbnails', - 'sort' => 35 - ], - [ - 'collection' => 'directus_settings', - 'field' => 'thumbnail_actions', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, - 'interface' => 'json', - 'locked' => 1, - 'width' => 'half', - 'note' => 'Defines how the thumbnail will be generated based on the requested dimensions', - 'sort' => 36 - ], - [ - 'collection' => 'directus_settings', - 'field' => 'thumbnail_not_found_location', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'options' => json_encode([ - 'iconRight' => 'broken_image' - ]), - 'locked' => 1, - 'width' => 'full', - 'note' => 'A fallback image used when thumbnail generation fails', - 'sort' => 37 - ], - [ - 'collection' => 'directus_settings', - 'field' => 'thumbnail_cache_ttl', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'numeric', - 'options' => json_encode([ - 'iconRight' => 'cached' - ]), - 'locked' => 1, - 'width' => 'half', - 'required' => 1, - 'note' => 'Seconds before browsers re-fetch thumbnails', - 'sort' => 38 - ], - [ - 'collection' => 'directus_settings', - 'field' => 'youtube_api', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'options' => json_encode([ - 'iconRight' => 'videocam' - ]), - 'locked' => 1, - 'width' => 'half', - 'note' => 'Allows fetching more YouTube Embed info', - 'sort' => 39 - ], - - // Users - // ----------------------------------------------------------------- - [ - 'collection' => 'directus_users', - 'field' => 'id', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'primary-key', - 'locked' => 1, - 'required' => 1, - 'hidden_detail' => 1, - 'sort' => 1 - ], - [ - 'collection' => 'directus_users', - 'field' => 'status', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STATUS, - 'interface' => 'status', - 'options' => json_encode([ - 'status_mapping' => [ - 'draft' => [ - 'name' => 'Draft', - 'text_color' => 'white', - 'background_color' => 'light-gray', - 'listing_subdued' => false, - 'listing_badge' => true, - 'soft_delete' => false, - ], - 'invited' => [ - 'name' => 'Invited', - 'text_color' => 'white', - 'background_color' => 'light-gray', - 'listing_subdued' => false, - 'listing_badge' => true, - 'soft_delete' => false, - ], - 'active' => [ - 'name' => 'Active', - 'text_color' => 'white', - 'background_color' => 'success', - 'listing_subdued' => false, - 'listing_badge' => false, - 'soft_delete' => false, - ], - 'suspended' => [ - 'name' => 'Suspended', - 'text_color' => 'white', - 'background_color' => 'light-gray', - 'listing_subdued' => false, - 'listing_badge' => true, - 'soft_delete' => false, - ], - 'deleted' => [ - 'name' => 'Deleted', - 'text_color' => 'white', - 'background_color' => 'danger', - 'listing_subdued' => false, - 'listing_badge' => true, - 'soft_delete' => true, - ] - ] - ]), - 'locked' => 1, - 'sort' => 2, - 'required' => 1 - ], - [ - 'collection' => 'directus_users', - 'field' => 'first_name', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'options' => json_encode([ - 'iconRight' => 'account_circle' - ]), - 'locked' => 1, - 'required' => 1, - 'sort' => 3, - 'width' => 'half' - ], - [ - 'collection' => 'directus_users', - 'field' => 'last_name', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'options' => json_encode([ - 'iconRight' => 'account_circle' - ]), - 'locked' => 1, - 'required' => 1, - 'sort' => 4, - 'width' => 'half' - ], - [ - 'collection' => 'directus_users', - 'field' => 'email', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'options' => json_encode([ - 'iconRight' => 'alternate_email' - ]), - 'locked' => 1, - 'validation' => '$email', - 'required' => 1, - 'sort' => 5, - 'width' => 'half' - ], - [ - 'collection' => 'directus_users', - 'field' => 'email_notifications', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, - 'interface' => 'toggle', - 'locked' => 1, - 'sort' => 6, - 'width' => 'half' - ], - [ - 'collection' => 'directus_users', - 'field' => 'password', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_HASH, - 'interface' => 'password', - 'locked' => 1, - 'required' => 1, - 'sort' => 7, - 'width' => 'half' - ], - [ - 'collection' => 'directus_users', - 'field' => 'role', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, - 'interface' => 'user-roles', - 'locked' => 1, - 'sort' => 8, - 'width' => 'half', - 'required' => 1 - ], - [ - 'collection' => 'directus_users', - 'field' => 'company', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'options' => json_encode([ - 'iconRight' => 'location_city' - ]), - 'sort' => 9, - 'width' => 'half' - ], - [ - 'collection' => 'directus_users', - 'field' => 'title', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'options' => json_encode([ - 'iconRight' => 'text_fields' - ]), - 'sort' => 10, - 'width' => 'half' - ], - [ - 'collection' => 'directus_users', - 'field' => 'timezone', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'dropdown', - 'options' => json_encode([ - 'choices' => [ - 'Pacific/Midway' => '(UTC-11:00) Midway Island', - 'Pacific/Samoa' => '(UTC-11:00) Samoa', - 'Pacific/Honolulu' => '(UTC-10:00) Hawaii', - 'US/Alaska' => '(UTC-09:00) Alaska', - 'America/Los_Angeles' => '(UTC-08:00) Pacific Time (US & Canada)', - 'America/Tijuana' => '(UTC-08:00) Tijuana', - 'US/Arizona' => '(UTC-07:00) Arizona', - 'America/Chihuahua' => '(UTC-07:00) Chihuahua', - 'America/Mexico/La_Paz' => '(UTC-07:00) La Paz', - 'America/Mazatlan' => '(UTC-07:00) Mazatlan', - 'US/Mountain' => '(UTC-07:00) Mountain Time (US & Canada)', - 'America/Managua' => '(UTC-06:00) Central America', - 'US/Central' => '(UTC-06:00) Central Time (US & Canada)', - 'America/Guadalajara' => '(UTC-06:00) Guadalajara', - 'America/Mexico_City' => '(UTC-06:00) Mexico City', - 'America/Monterrey' => '(UTC-06:00) Monterrey', - 'Canada/Saskatchewan' => '(UTC-06:00) Saskatchewan', - 'America/Bogota' => '(UTC-05:00) Bogota', - 'US/Eastern' => '(UTC-05:00) Eastern Time (US & Canada)', - 'US/East-Indiana' => '(UTC-05:00) Indiana (East)', - 'America/Lima' => '(UTC-05:00) Lima', - 'America/Quito' => '(UTC-05:00) Quito', - 'Canada/Atlantic' => '(UTC-04:00) Atlantic Time (Canada)', - 'America/New_York' => '(UTC-04:00) New York', - 'America/Caracas' => '(UTC-04:30) Caracas', - 'America/La_Paz' => '(UTC-04:00) La Paz', - 'America/Santiago' => '(UTC-04:00) Santiago', - 'America/Santo_Domingo' => '(UTC-04:00) Santo Domingo', - 'Canada/Newfoundland' => '(UTC-03:30) Newfoundland', - 'America/Sao_Paulo' => '(UTC-03:00) Brasilia', - 'America/Argentina/Buenos_Aires' => '(UTC-03:00) Buenos Aires', - 'America/Argentina/GeorgeTown' => '(UTC-03:00) Georgetown', - 'America/Godthab' => '(UTC-03:00) Greenland', - 'America/Noronha' => '(UTC-02:00) Mid-Atlantic', - 'Atlantic/Azores' => '(UTC-01:00) Azores', - 'Atlantic/Cape_Verde' => '(UTC-01:00) Cape Verde Is.', - 'Africa/Casablanca' => '(UTC+00:00) Casablanca', - 'Europe/Edinburgh' => '(UTC+00:00) Edinburgh', - 'Etc/Greenwich' => '(UTC+00:00) Greenwich Mean Time : Dublin', - 'Europe/Lisbon' => '(UTC+00:00) Lisbon', - 'Europe/London' => '(UTC+00:00) London', - 'Africa/Monrovia' => '(UTC+00:00) Monrovia', - 'UTC' => '(UTC+00:00) UTC', - 'Europe/Amsterdam' => '(UTC+01:00) Amsterdam', - 'Europe/Belgrade' => '(UTC+01:00) Belgrade', - 'Europe/Berlin' => '(UTC+01:00) Berlin', - 'Europe/Bern' => '(UTC+01:00) Bern', - 'Europe/Bratislava' => '(UTC+01:00) Bratislava', - 'Europe/Brussels' => '(UTC+01:00) Brussels', - 'Europe/Budapest' => '(UTC+01:00) Budapest', - 'Europe/Copenhagen' => '(UTC+01:00) Copenhagen', - 'Europe/Ljubljana' => '(UTC+01:00) Ljubljana', - 'Europe/Madrid' => '(UTC+01:00) Madrid', - 'Europe/Paris' => '(UTC+01:00) Paris', - 'Europe/Prague' => '(UTC+01:00) Prague', - 'Europe/Rome' => '(UTC+01:00) Rome', - 'Europe/Sarajevo' => '(UTC+01:00) Sarajevo', - 'Europe/Skopje' => '(UTC+01:00) Skopje', - 'Europe/Stockholm' => '(UTC+01:00) Stockholm', - 'Europe/Vienna' => '(UTC+01:00) Vienna', - 'Europe/Warsaw' => '(UTC+01:00) Warsaw', - 'Africa/Lagos' => '(UTC+01:00) West Central Africa', - 'Europe/Zagreb' => '(UTC+01:00) Zagreb', - 'Europe/Athens' => '(UTC+02:00) Athens', - 'Europe/Bucharest' => '(UTC+02:00) Bucharest', - 'Africa/Cairo' => '(UTC+02:00) Cairo', - 'Africa/Harare' => '(UTC+02:00) Harare', - 'Europe/Helsinki' => '(UTC+02:00) Helsinki', - 'Europe/Istanbul' => '(UTC+02:00) Istanbul', - 'Asia/Jerusalem' => '(UTC+02:00) Jerusalem', - 'Europe/Kyiv' => '(UTC+02:00) Kyiv', - 'Africa/Johannesburg' => '(UTC+02:00) Pretoria', - 'Europe/Riga' => '(UTC+02:00) Riga', - 'Europe/Sofia' => '(UTC+02:00) Sofia', - 'Europe/Tallinn' => '(UTC+02:00) Tallinn', - 'Europe/Vilnius' => '(UTC+02:00) Vilnius', - 'Asia/Baghdad' => '(UTC+03:00) Baghdad', - 'Asia/Kuwait' => '(UTC+03:00) Kuwait', - 'Europe/Minsk' => '(UTC+03:00) Minsk', - 'Africa/Nairobi' => '(UTC+03:00) Nairobi', - 'Asia/Riyadh' => '(UTC+03:00) Riyadh', - 'Europe/Volgograd' => '(UTC+03:00) Volgograd', - 'Asia/Tehran' => '(UTC+03:30) Tehran', - 'Asia/Abu_Dhabi' => '(UTC+04:00) Abu Dhabi', - 'Asia/Baku' => '(UTC+04:00) Baku', - 'Europe/Moscow' => '(UTC+04:00) Moscow', - 'Asia/Muscat' => '(UTC+04:00) Muscat', - 'Europe/St_Petersburg' => '(UTC+04:00) St. Petersburg', - 'Asia/Tbilisi' => '(UTC+04:00) Tbilisi', - 'Asia/Yerevan' => '(UTC+04:00) Yerevan', - 'Asia/Kabul' => '(UTC+04:30) Kabul', - 'Asia/Islamabad' => '(UTC+05:00) Islamabad', - 'Asia/Karachi' => '(UTC+05:00) Karachi', - 'Asia/Tashkent' => '(UTC+05:00) Tashkent', - 'Asia/Calcutta' => '(UTC+05:30) Chennai', - 'Asia/Kolkata' => '(UTC+05:30) Kolkata', - 'Asia/Mumbai' => '(UTC+05:30) Mumbai', - 'Asia/New_Delhi' => '(UTC+05:30) New Delhi', - 'Asia/Sri_Jayawardenepura' => '(UTC+05:30) Sri Jayawardenepura', - 'Asia/Katmandu' => '(UTC+05:45) Kathmandu', - 'Asia/Almaty' => '(UTC+06:00) Almaty', - 'Asia/Astana' => '(UTC+06:00) Astana', - 'Asia/Dhaka' => '(UTC+06:00) Dhaka', - 'Asia/Yekaterinburg' => '(UTC+06:00) Ekaterinburg', - 'Asia/Rangoon' => '(UTC+06:30) Rangoon', - 'Asia/Bangkok' => '(UTC+07:00) Bangkok', - 'Asia/Hanoi' => '(UTC+07:00) Hanoi', - 'Asia/Jakarta' => '(UTC+07:00) Jakarta', - 'Asia/Novosibirsk' => '(UTC+07:00) Novosibirsk', - 'Asia/Beijing' => '(UTC+08:00) Beijing', - 'Asia/Chongqing' => '(UTC+08:00) Chongqing', - 'Asia/Hong_Kong' => '(UTC+08:00) Hong Kong', - 'Asia/Krasnoyarsk' => '(UTC+08:00) Krasnoyarsk', - 'Asia/Kuala_Lumpur' => '(UTC+08:00) Kuala Lumpur', - 'Australia/Perth' => '(UTC+08:00) Perth', - 'Asia/Singapore' => '(UTC+08:00) Singapore', - 'Asia/Taipei' => '(UTC+08:00) Taipei', - 'Asia/Ulan_Bator' => '(UTC+08:00) Ulaan Bataar', - 'Asia/Urumqi' => '(UTC+08:00) Urumqi', - 'Asia/Irkutsk' => '(UTC+09:00) Irkutsk', - 'Asia/Osaka' => '(UTC+09:00) Osaka', - 'Asia/Sapporo' => '(UTC+09:00) Sapporo', - 'Asia/Seoul' => '(UTC+09:00) Seoul', - 'Asia/Tokyo' => '(UTC+09:00) Tokyo', - 'Australia/Adelaide' => '(UTC+09:30) Adelaide', - 'Australia/Darwin' => '(UTC+09:30) Darwin', - 'Australia/Brisbane' => '(UTC+10:00) Brisbane', - 'Australia/Canberra' => '(UTC+10:00) Canberra', - 'Pacific/Guam' => '(UTC+10:00) Guam', - 'Australia/Hobart' => '(UTC+10:00) Hobart', - 'Australia/Melbourne' => '(UTC+10:00) Melbourne', - 'Pacific/Port_Moresby' => '(UTC+10:00) Port Moresby', - 'Australia/Sydney' => '(UTC+10:00) Sydney', - 'Asia/Yakutsk' => '(UTC+10:00) Yakutsk', - 'Asia/Vladivostok' => '(UTC+11:00) Vladivostok', - 'Pacific/Auckland' => '(UTC+12:00) Auckland', - 'Pacific/Fiji' => '(UTC+12:00) Fiji', - 'Pacific/Kwajalein' => '(UTC+12:00) International Date Line West', - 'Asia/Kamchatka' => '(UTC+12:00) Kamchatka', - 'Asia/Magadan' => '(UTC+12:00) Magadan', - 'Pacific/Marshall_Is' => '(UTC+12:00) Marshall Is.', - 'Asia/New_Caledonia' => '(UTC+12:00) New Caledonia', - 'Asia/Solomon_Is' => '(UTC+12:00) Solomon Is.', - 'Pacific/Wellington' => '(UTC+12:00) Wellington', - 'Pacific/Tongatapu' => '(UTC+13:00) Nuku\'alofa' - ], - 'placeholder' => 'Choose a timezone...' - ]), - 'locked' => 1, - 'sort' => 11, - 'width' => 'half', - 'required' => 1 - ], - [ - 'collection' => 'directus_users', - 'field' => 'locale', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'language', - 'options' => json_encode([ - 'limit' => true - ]), - 'locked' => 1, - 'sort' => 12, - 'width' => 'half', - 'required' => 0 - ], - [ - 'collection' => 'directus_users', - 'field' => 'avatar', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_FILE, - 'interface' => 'file', - 'locked' => 1, - 'sort' => 13 - ], - [ - 'collection' => 'directus_users', - 'field' => 'theme', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'radio-buttons', - 'options' => json_encode([ - 'format' => true, - 'choices' => [ - 'auto' => 'Auto', - 'light' => 'Light', - 'dark' => 'Dark' - ] - ]), - 'locked' => 1, - 'readonly' => 0, - 'sort' => 14 - ], - [ - 'collection' => 'directus_users', - 'field' => '2fa_secret', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => '2fa-secret', - 'locked' => 1, - 'readonly' => 1, - 'sort' => 15 - ], - [ - 'collection' => 'directus_users', - 'field' => 'locale_options', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, - 'interface' => 'json', - 'locked' => 1, - 'hidden_browse' => 1, - 'hidden_detail' => 1, - 'sort' => 16 - ], - [ - 'collection' => 'directus_users', - 'field' => 'token', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1, - 'hidden_detail' => 1, - 'hidden_browse' => 1, - 'sort' => 17 - ], - [ - 'collection' => 'directus_users', - 'field' => 'last_access_on', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_DATETIME, - 'interface' => 'datetime', - 'locked' => 1, - 'readonly' => 1, - 'hidden_detail' => 1, - 'sort' => 18 - ], - [ - 'collection' => 'directus_users', - 'field' => 'last_page', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1, - 'readonly' => 1, - 'hidden_detail' => 1, - 'hidden_browse' => 1, - 'sort' => 19 - ], - [ - 'collection' => 'directus_users', - 'field' => 'external_id', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'locked' => 1, - 'readonly' => 1, - 'hidden_detail' => 20 - ], - - // User Session - // ----------------------------------------------------------------- - [ - 'collection' => 'directus_user_sessions', - 'field' => 'id', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'primary-key', - 'locked' => 1, - 'required' => 1, - 'hidden_detail' => 1 - ], - [ - 'collection' => 'directus_user_sessions', - 'field' => 'user', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_USER, - 'required' => 1, - 'interface' => 'user' - ], - [ - 'collection' => 'directus_user_sessions', - 'field' => 'token_type', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input' - ], - [ - 'collection' => 'directus_user_sessions', - 'field' => 'token', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input' - ], - [ - 'collection' => 'directus_user_sessions', - 'field' => 'ip_address', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input' - ], - [ - 'collection' => 'directus_user_sessions', - 'field' => 'user_agent', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input' - ], - [ - 'collection' => 'directus_user_sessions', - 'field' => 'created_on', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_DATETIME, - 'interface' => 'datetime' - ], - [ - 'collection' => 'directus_user_sessions', - 'field' => 'token_expired_at', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_DATETIME, - 'interface' => 'datetime' - ], - - // Webhooks - // ----------------------------------------------------------------- - [ - 'collection' => 'directus_webhooks', - 'field' => 'id', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, - 'interface' => 'primary-key', - 'locked' => 1, - 'required' => 1, - 'hidden_detail' => 1 - ], - [ - 'collection' => 'directus_webhooks', - 'field' => 'status', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STATUS, - 'interface' => 'status', - 'options' => json_encode([ - 'status_mapping' => [ - 'active' => [ - 'name' => 'Active', - 'value' => 'active', - 'text_color' => 'white', - 'background_color' => 'green', - 'browse_subdued' => false, - 'browse_badge' => true, - 'soft_delete' => false, - 'published' => true, - ], - 'inactive' => [ - 'name' => 'Inactive', - 'value' => 'inactive', - 'text_color' => 'white', - 'background_color' => 'blue-grey', - 'browse_subdued' => true, - 'browse_badge' => true, - 'soft_delete' => false, - 'published' => false, - ] - ] - ]), - 'locked' => 1, - 'width' => 'full', - 'sort' => 1 - ], - [ - 'collection' => 'directus_webhooks', - 'field' => 'http_action', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'dropdown', - 'required' => 1, - 'options' => json_encode([ - 'choices' => [ - 'get' => 'GET', - 'post' => 'POST' - ] - ]), - 'locked' => 1, - 'width' => 'half-space', - 'sort' => 2 - ], - [ - 'collection' => 'directus_webhooks', - 'field' => 'url', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'options' => json_encode([ - 'placeholder' => 'https://example.com', - 'iconRight' => 'link' - ]), - 'required' => 1, - 'locked' => 1, - 'width' => 'full', - 'note' => '', - 'sort' => 3 - ], - [ - 'collection' => 'directus_webhooks', - 'field' => 'collection', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'collections', - 'required' => 1, - 'locked' => 1, - 'width' => 'half', - 'note' => '', - 'sort' => 4 - ], - [ - 'collection' => 'directus_webhooks', - 'field' => 'directus_action', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'dropdown', - 'required' => 1, - 'options' => json_encode([ - 'choices' => [ - 'item.create:after' => 'Create', - 'item.update:after' => 'Update', - 'item.delete:after' => 'Delete', - ] - ]), - 'locked' => 1, - 'width' => 'half', - 'note' => '', - 'sort' => 5 - ], - [ - 'collection' => 'directus_webhooks', - 'field' => 'info', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_ALIAS, - 'interface' => 'divider', - 'options' => json_encode([ - 'style' => 'medium', - 'title' => 'How Webhooks Work', - 'hr' => true, - 'margin' => false, - 'description' => 'When the selected action occurs for the selected collection, Directus will send an HTTP request to the above URL.' - ]), - 'locked' => 1, - 'width' => 'full', - 'hidden_browse' => 1, - 'sort' => 6 - ], - ]; - - $files = $this->table('directus_fields'); - $files->insert($data)->save(); - } -} diff --git a/migrations/db/seeds/RelationsSeeder.php b/migrations/db/seeds/RelationsSeeder.php deleted file mode 100644 index 41ae9188fd..0000000000 --- a/migrations/db/seeds/RelationsSeeder.php +++ /dev/null @@ -1,80 +0,0 @@ - 'directus_activity', - 'field_many' => 'action_by', - 'collection_one' => 'directus_users' - ], - [ - 'collection_many' => 'directus_collections_presets', - 'field_many' => 'user', - 'collection_one' => 'directus_users' - ], - [ - 'collection_many' => 'directus_collections_presets', - 'field_many' => 'group', - 'collection_one' => 'directus_groups' - ], - [ - 'collection_many' => 'directus_fields', - 'field_many' => 'collection', - 'collection_one' => 'directus_collections', - 'field_one' => 'fields' - ], - [ - 'collection_many' => 'directus_files', - 'field_many' => 'uploaded_by', - 'collection_one' => 'directus_users' - ], - [ - 'collection_many' => 'directus_files', - 'field_many' => 'folder', - 'collection_one' => 'directus_folders' - ], - [ - 'collection_many' => 'directus_folders', - 'field_many' => 'parent_folder', - 'collection_one' => 'directus_folders' - ], - [ - 'collection_many' => 'directus_permissions', - 'field_many' => 'group', - 'collection_one' => 'directus_groups' - ], - [ - 'collection_many' => 'directus_revisions', - 'field_many' => 'activity', - 'collection_one' => 'directus_activity' - ], - [ - 'collection_many' => 'directus_users', - 'field_many' => 'role', - 'collection_one' => 'directus_roles', - 'field_one' => 'users' - ], - [ - 'collection_many' => 'directus_users', - 'field_many' => 'avatar', - 'collection_one' => 'directus_files' - ] - ]; - - $files = $this->table('directus_relations'); - $files->insert($data)->save(); - } -} diff --git a/migrations/db/seeds/RolesSeeder.php b/migrations/db/seeds/RolesSeeder.php deleted file mode 100644 index b245c76522..0000000000 --- a/migrations/db/seeds/RolesSeeder.php +++ /dev/null @@ -1,33 +0,0 @@ - 1, - 'name' => 'Administrator', - 'description' => 'Admins have access to all managed data within the system by default' - ], - [ - 'id' => 2, - 'name' => 'Public', - 'description' => 'Controls what API data is publicly available without authenticating' - ] - ]; - - $groups = $this->table('directus_roles'); - $groups->insert($data)->save(); - } -} diff --git a/migrations/db/seeds/SettingsSeeder.php b/migrations/db/seeds/SettingsSeeder.php deleted file mode 100644 index 86b1920296..0000000000 --- a/migrations/db/seeds/SettingsSeeder.php +++ /dev/null @@ -1,111 +0,0 @@ - 'project_url', - 'value' => '' - ], - [ - 'key' => 'project_logo', - 'value' => '' - ], - [ - 'key' => 'project_color', - 'value' => 'blue-grey-900', - ], - [ - 'key' => 'project_foreground', - 'value' => '', - ], - [ - 'key' => 'project_background', - 'value' => '', - ], - [ - 'key' => 'default_locale', - 'value' => 'en-US', - ], - [ - 'key' => 'telemetry', - 'value' => '1', - ], - [ - 'key' => 'default_limit', - 'value' => '200' - ], - [ - 'key' => 'sort_null_last', - 'value' => '1' - ], - [ - 'key' => 'password_policy', - 'value' => '' - ], - [ - 'key' => 'auto_sign_out', - 'value' => '10080' - ], - [ - 'key' => 'login_attempts_allowed', - 'value' => '10' - ], - [ - 'key' => 'trusted_proxies', - 'value' => '' - ], - [ - 'key' => 'file_naming', - 'value' => 'uuid' - ], - [ - 'key' => 'file_max_size', - 'value' => '100MB' - ], - [ - 'key' => 'file_mimetype_whitelist', - 'value' => '' - ], - [ - 'key' => 'thumbnail_dimensions', - 'value' => '200x200' - ], - [ - 'key' => 'thumbnail_quality_tags', - 'value' => '{"poor": 25, "good": 50, "better": 75, "best": 100}' - ], - [ - 'key' => 'thumbnail_actions', - 'value' => '{"contain":{"options":{"resizeCanvas":false,"position":"center","resizeRelative":false,"canvasBackground":"ccc"}},"crop":{"options":{"position":"center"}}}' - ], - [ - 'key' => 'thumbnail_not_found_location', - 'value' => '' - ], - [ - 'key' => 'thumbnail_cache_ttl', - 'value' => '86400' - ], - [ - 'key' => 'youtube_api_key', - 'value' => '' - ] - ]; - - $groups = $this->table('directus_settings'); - $groups->insert($data)->save(); - } -} diff --git a/migrations/install/20180220023123_create_fields_table.php b/migrations/install/20180220023123_create_fields_table.php new file mode 100644 index 0000000000..536227d22d --- /dev/null +++ b/migrations/install/20180220023123_create_fields_table.php @@ -0,0 +1,252 @@ +table('directus_fields', ['signed' => false]); + + $table->addColumn('collection', 'string', [ + 'limit' => 64, + 'null' => false + ]); + $table->addColumn('field', 'string', [ + 'limit' => 64, + 'null' => false + ]); + $table->addColumn('type', 'string', [ + 'limit' => 64, + 'null' => false + ]); + $table->addColumn('interface', 'string', [ + 'limit' => 64, + 'null' => true, + 'default' => null, + ]); + $table->addColumn('options', 'text', [ + 'null' => true, + 'default' => null + ]); + $table->addColumn('locked', 'boolean', [ + 'signed' => false, + 'null' => false, + 'default' => false + ]); + $table->addColumn('validation', 'string', [ + 'limit' => 255, + 'null' => true, + 'default' => null + ]); + $table->addColumn('required', 'boolean', [ + 'signed' => false, + 'null' => false, + 'default' => false + ]); + $table->addColumn('readonly', 'boolean', [ + 'signed' => false, + 'null' => false, + 'default' => false + ]); + $table->addColumn('hidden_detail', 'boolean', [ + 'signed' => false, + 'null' => false, + 'default' => 0 + ]); + $table->addColumn('hidden_browse', 'boolean', [ + 'signed' => false, + 'null' => false, + 'default' => 0 + ]); + $table->addColumn('sort', 'integer', [ + 'signed' => false, + 'null' => true, + 'default' => null + ]); + $table->addColumn('width', 'string', [ + 'limit' => 50, + 'null' => true, + 'default' => 'full' + ]); + $table->addColumn('group', 'integer', [ + 'signed' => false, + 'null' => true, + 'default' => null + ]); + $table->addColumn('note', 'string', [ + 'limit' => 1024, + 'null' => true, + 'default' => null + ]); + $table->addColumn('translation', 'text', [ + 'null' => true, + 'default' => null + ]); + + $table->addIndex(['collection', 'field'], [ + 'unique' => true, + 'name' => 'idx_collection_field' + ]); + + $table->create(); + + $data = [ + [ + 'collection' => 'directus_fields', + 'field' => 'id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'primary-key', + 'locked' => 1, + 'required' => 1, + 'hidden_detail' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'collection', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, + 'interface' => 'many-to-one', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'field', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'type', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'primary-key', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'interface', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'primary-key', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'options', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'json', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'locked', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'translation', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'repeater', + 'locked' => 1, + 'options' => '{ + "fields": [ + { + "field": "locale", + "type": "string", + "interface": "language", + "options": { + "limit": true + }, + "width": "half" + }, + { + "field": "translation", + "type": "string", + "interface": "text-input", + "width": "half" + } + ] + }' + ], + [ + 'collection' => 'directus_fields', + 'field' => 'readonly', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'validation', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + ], + [ + 'collection' => 'directus_fields', + 'field' => 'required', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'sort', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_SORT, + 'interface' => 'sort', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'note', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'hidden_detail', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'hidden_browse', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'width', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'numeric', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'group', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, + 'interface' => 'many-to-one', + 'locked' => 1 + ], + ]; + + foreach($data as $value){ + if(!$this->checkFieldExist($value['collection'], $value['field'])){ + $fileds = $this->table('directus_fields'); + $fileds->insert($value)->save(); + } + } + } + + public function checkFieldExist($collection,$field){ + $checkSql = sprintf('SELECT 1 FROM `directus_fields` WHERE `collection` = "%s" AND `field` = "%s";', $collection, $field); + return $this->query($checkSql)->fetch(); + } +} diff --git a/migrations/install/20180220023138_create_activity_table.php b/migrations/install/20180220023138_create_activity_table.php new file mode 100644 index 0000000000..d1ed6aa8c9 --- /dev/null +++ b/migrations/install/20180220023138_create_activity_table.php @@ -0,0 +1,220 @@ +table('directus_activity', ['signed' => false]); + + $table->addColumn('action', 'string', [ + 'limit' => 45, + 'null' => false + ]); + + $table->addColumn('action_by', 'integer', [ + 'signed' => false, + 'null' => false, + 'default' => 0 + ]); + + $table->addColumn('action_on', 'datetime', [ + 'default' => null + ]); + + $table->addColumn('ip', 'string', [ + 'limit' => 50, + 'default' => null + ]); + + $table->addColumn('user_agent', 'string', [ + 'limit' => 255 + ]); + + $table->addColumn('collection', 'string', [ + 'limit' => 64, + 'null' => false + ]); + + $table->addColumn('item', 'string',[ + 'limit' => 255 + ]); + + $table->addColumn('edited_on', 'datetime', [ + 'null' => true, + 'default' => null + ]); + + $table->addColumn('comment', 'text', [ + 'null' => true, + 'encoding' => 'utf8mb4' + ]); + + $table->addColumn('comment_deleted_on', 'datetime', [ + 'null' => true, + 'default' => null + ]); + + $table->create(); + + $data = [ + [ + 'collection' => 'directus_activity', + 'field' => 'id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'primary-key', + 'locked' => 1, + 'readonly' => 1, + 'required' => 1, + 'hidden_detail' => 1 + ], + [ + 'collection' => 'directus_activity', + 'field' => 'action', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'change_history' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 1, + 'width' => 'full' + ], + [ + 'collection' => 'directus_activity', + 'field' => 'collection', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'collections', + 'options' => json_encode([ + 'iconRight' => 'list_alt', + 'include_system' => true + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 2, + 'width' => 'half' + ], + [ + 'collection' => 'directus_activity', + 'field' => 'item', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'link' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 3, + 'width' => 'half' + ], + [ + 'collection' => 'directus_activity', + 'field' => 'action_by', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'user', + 'options' => json_encode([ + 'iconRight' => 'account_circle' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 4, + 'width' => 'half' + ], + [ + 'collection' => 'directus_activity', + 'field' => 'action_on', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_DATETIME, + 'interface' => 'datetime', + 'options' => json_encode([ + 'showRelative' => true, + 'iconRight' => 'calendar_today' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 5, + 'width' => 'half' + ], + [ + 'collection' => 'directus_activity', + 'field' => 'edited_on', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_DATETIME, + 'interface' => 'datetime', + 'options' => json_encode([ + 'showRelative' => true, + 'iconRight' => 'edit' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 6, + 'width' => 'half' + ], + [ + 'collection' => 'directus_activity', + 'field' => 'comment_deleted_on', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_DATETIME, + 'interface' => 'datetime', + 'options' => json_encode([ + 'showRelative' => true, + 'iconRight' => 'delete_outline' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 7, + 'width' => 'half' + ], + [ + 'collection' => 'directus_activity', + 'field' => 'ip', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'my_location' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 8, + 'width' => 'half' + ], + [ + 'collection' => 'directus_activity', + 'field' => 'user_agent', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'devices_other' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 9, + 'width' => 'half' + ], + [ + 'collection' => 'directus_activity', + 'field' => 'comment', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'textarea', + 'locked' => 1, + 'readonly' => 1, + 'sort' => 10, + 'width' => 'full' + ], + ]; + + foreach($data as $value){ + if(!$this->checkFieldExist($value['collection'], $value['field'])){ + $fileds = $this->table('directus_fields'); + $fileds->insert($value)->save(); + } + } + } + + public function checkFieldExist($collection,$field){ + $checkSql = sprintf('SELECT 1 FROM `directus_fields` WHERE `collection` = "%s" AND `field` = "%s";', $collection, $field); + return $this->query($checkSql)->fetch(); + } +} diff --git a/migrations/install/20180220023152_create_collections_presets_table.php b/migrations/install/20180220023152_create_collections_presets_table.php new file mode 100644 index 0000000000..19860a4b00 --- /dev/null +++ b/migrations/install/20180220023152_create_collections_presets_table.php @@ -0,0 +1,218 @@ +table('directus_collection_presets', ['signed' => false]); + + $table->addColumn('title', 'string', [ + 'limit' => 255, + 'null' => true, + 'default' => null, + 'encoding' => 'utf8mb4' + ]); + $table->addColumn('user', 'integer', [ + 'signed' => false, + 'null' => true + ]); + $table->addColumn('role', 'integer', [ + 'signed' => false, + 'null' => true + ]); + $table->addColumn('collection', 'string', [ + 'limit' => 64, + 'null' => false + ]); + $table->addColumn('search_query', 'string', [ + 'limit' => 100, + 'null' => true, + 'default' => null + ]); + $table->addColumn('filters', 'text', [ + 'null' => true, + 'default' => null + ]); + $table->addColumn('view_type', 'string', [ + 'limit' => 100, + 'null' => false, + 'default' => 'tabular' + ]); + $table->addColumn('view_query', 'text', [ + 'null' => true, + 'default' => null + ]); + $table->addColumn('view_options', 'text', [ + 'null' => true, + 'default' => null + ]); + $table->addColumn('translation', 'text', [ + 'null' => true, + 'default' => null + ]); + $table->addIndex(['user', 'collection', 'title'], [ + 'unique' => true, + 'name' => 'idx_user_collection_title' + ]); + + $table->create(); + + $data = [ + [ + 'collection' => 'directus_collection_presets', + 'field' => 'id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'primary-key', + 'locked' => 1 + ], + [ + 'collection' => 'directus_collection_presets', + 'field' => 'title', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_collection_presets', + 'field' => 'user', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'user', + 'locked' => 1 + ], + [ + 'collection' => 'directus_collection_presets', + 'field' => 'role', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, + 'interface' => 'many-to-one', + 'locked' => 1 + ], + [ + 'collection' => 'directus_collection_presets', + 'field' => 'collection', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, + 'interface' => 'many-to-one', + 'locked' => 1 + ], + [ + 'collection' => 'directus_collection_presets', + 'field' => 'search_query', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_collection_presets', + 'field' => 'filters', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'json', + 'locked' => 1 + ], + [ + 'collection' => 'directus_collection_presets', + 'field' => 'view_options', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'json', + 'locked' => 1 + ], + [ + 'collection' => 'directus_collection_presets', + 'field' => 'view_type', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_collection_presets', + 'field' => 'view_query', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'json', + 'locked' => 1 + ], + ]; + + foreach($data as $value){ + if(!$this->checkFieldExist($value['collection'], $value['field'])){ + $fileds = $this->table('directus_fields'); + $fileds->insert($value)->save(); + } + } + + $result = [ + [ + 'collection' => 'directus_activity', + 'view_type' => 'timeline', + 'view_query' => json_encode([ + 'timeline' => [ + 'sort' => '-action_on' + ] + ]), + 'view_options' => json_encode([ + 'timeline' => [ + 'date' => 'action_on', + 'title' => '{{ action }} by {{ action_by.first_name }} {{ action_by.last_name }} (#{{ item }})', + 'content' => 'collection', + 'color' => 'action' + ] + ]) + ], + [ + 'collection' => 'directus_files', + 'view_type' => 'cards', + 'view_options' => json_encode([ + 'cards' => [ + 'title' => 'title', + 'subtitle' => 'type', + 'content' => 'description', + 'src' => 'data' + ] + ]) + ], + [ + 'collection' => 'directus_users', + 'view_type' => 'cards', + 'view_options' => json_encode([ + 'cards' => [ + 'title' => 'first_name', + 'subtitle' => 'last_name', + 'content' => 'title', + 'src' => 'avatar', + 'icon' => 'person' + ] + ]) + ], + [ + 'collection' => 'directus_webhooks', + 'view_type' => 'tabular', + 'view_query' => json_encode([ + 'tabular' => [ + 'fields' => 'status,http_action,url,collection,directus_action' + ] + ]), + 'view_options' => json_encode([ + 'tabular' => [ + 'widths' => [ + 'status' => 32, + 'http_action' => 72, + 'url' => 200, + 'collection' => 200, + 'directus_action' => 200 + ] + ] + ]) + ] + ]; + + $files = $this->table('directus_collection_presets'); + $files->insert($result)->save(); + } + + public function checkFieldExist($collection,$field){ + $checkSql = sprintf('SELECT 1 FROM `directus_fields` WHERE `collection` = "%s" AND `field` = "%s";', $collection, $field); + return $this->query($checkSql)->fetch(); + } +} diff --git a/migrations/install/20180220023157_create_collections_table.php b/migrations/install/20180220023157_create_collections_table.php new file mode 100644 index 0000000000..c9fdee5698 --- /dev/null +++ b/migrations/install/20180220023157_create_collections_table.php @@ -0,0 +1,167 @@ +table('directus_collections', [ + 'id' => false, + 'primary_key' => 'collection' + ]); + + $table->addColumn('collection', 'string', [ + 'limit' => 64, + 'null' => false + ]); + $table->addColumn('managed', 'boolean', [ + 'signed' => false, + 'null' => false, + 'default' => true + ]); + $table->addColumn('hidden', 'boolean', [ + 'signed' => false, + 'null' => false, + 'default' => false + ]); + $table->addColumn('single', 'boolean', [ + 'signed' => false, + 'null' => false, + 'default' => false + ]); + $table->addColumn('icon', 'string', [ + 'limit' => 30, + 'null' => true, + 'default' => null + ]); + $table->addColumn('note', 'string', [ + 'limit' => 255, + 'null' => true, + 'default' => null + ]); + $table->addColumn('translation', 'text', [ + 'null' => true, + 'default' => null + ]); + + $table->create(); + $data = [ + [ + 'collection' => 'directus_collections', + 'field' => 'fields', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_O2M, + 'interface' => 'one-to-many', + 'locked' => 1, + 'hidden_detail' => 1, + 'hidden_browse' => 1, + 'sort' => 1 + ], + [ + 'collection' => 'directus_collections', + 'field' => 'collection', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'primary-key', + 'locked' => 1, + 'readonly' => 1, + 'required' => 1, + 'sort' => 2, + 'width' => 'half' + ], + [ + 'collection' => 'directus_collections', + 'field' => 'note', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'sort' => 3, + 'width' => 'half', + 'note' => 'An internal description.' + ], + [ + 'collection' => 'directus_collections', + 'field' => 'managed', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1, + 'sort' => 4, + 'width' => 'half', + 'hidden_detail' => 1, + 'note' => '[Learn More](https://docs.directus.io/guides/collections.html#managing-collections).' + ], + [ + 'collection' => 'directus_collections', + 'field' => 'hidden', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1, + 'sort' => 5, + 'width' => 'half', + 'note' => '[Learn More](https://docs.directus.io/guides/collections.html#hidden).' + ], + [ + 'collection' => 'directus_collections', + 'field' => 'single', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1, + 'sort' => 6, + 'width' => 'half', + 'note' => '[Learn More](https://docs.directus.io/guides/collections.html#single).' + ], + [ + 'collection' => 'directus_collections', + 'field' => 'translation', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'repeater', + 'locked' => 1, + 'sort' => 7, + 'hidden_detail' => 0, + 'options' => '{ + "fields": [ + { + "field": "locale", + "type": "string", + "interface": "language", + "options": { + "limit": true + }, + "width": "half" + }, + { + "field": "translation", + "type": "string", + "interface": "text-input", + "width": "half" + } + ] + }' + ], + [ + 'collection' => 'directus_collections', + 'field' => 'icon', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'icon', + 'locked' => 1, + 'sort' => 8, + 'note' => 'The icon shown in the App\'s navigation sidebar.' + ], + + ]; + + foreach($data as $value){ + if(!$this->checkFieldExist($value['collection'], $value['field'])){ + $fileds = $this->table('directus_fields'); + $fileds->insert($value)->save(); + } + } + } + + public function checkFieldExist($collection,$field){ + $checkSql = sprintf('SELECT 1 FROM `directus_fields` WHERE `collection` = "%s" AND `field` = "%s";', $collection, $field); + return $this->query($checkSql)->fetch(); + } +} diff --git a/migrations/install/20180220023208_create_files_table.php b/migrations/install/20180220023208_create_files_table.php new file mode 100644 index 0000000000..a536c227f2 --- /dev/null +++ b/migrations/install/20180220023208_create_files_table.php @@ -0,0 +1,399 @@ +table('directus_files', ['signed' => false]); + + $table->addColumn('storage', 'string', [ + 'limit' => 50, + 'null' => false, + 'default' => 'local' + ]); + $table->addColumn('private_hash', 'string', [ + 'limit' => 16, + 'null' => true, + 'default' => null + ]); + $table->addColumn('filename_disk', 'string', [ + 'limit' => 255, + 'null' => false + ]); + $table->addColumn('filename_download', 'string', [ + 'limit' => 255, + 'null' => false + ]); + $table->addColumn('title', 'string', [ + 'limit' => 255, + 'null' => true, + 'default' => null + ]); + $table->addColumn('type', 'string', [ + 'limit' => 255, + 'null' => true, + 'default' => null // unknown type? + ]); + $table->addColumn('uploaded_by', 'integer', [ + 'signed' => false, + 'null' => false + ]); + // TODO: Make directus set this value to whatever default is on the server (UTC) + // In MySQL 5.5 and below doesn't support CURRENT TIMESTAMP on datetime as default + $table->addColumn('uploaded_on', 'datetime', [ + 'null' => false + ]); + $table->addColumn('charset', 'string', [ + 'limit' => 50, + 'null' => true, + 'default' => null + ]); + $table->addColumn('filesize', 'integer', [ + 'signed' => false, + 'default' => 0 + ]); + $table->addColumn('width', 'integer', [ + 'signed' => false, + 'null' => true, + 'default' => null + ]); + $table->addColumn('height', 'integer', [ + 'signed' => false, + 'null' => true, + 'default' => null + ]); + $table->addColumn('duration', 'integer', [ + 'signed' => true, + 'null' => true, + 'default' => null + ]); + $table->addColumn('embed', 'string', [ + 'limit' => 200, + 'null' => true, + 'default' => NULL + ]); + $table->addColumn('folder', 'integer', [ + 'signed' => false, + 'null' => true, + 'default' => null + ]); + $table->addColumn('description', 'text', [ + 'null' => true, + 'default' => null + ]); + $table->addColumn('location', 'string', [ + 'limit' => 200, + 'null' => true, + 'default' => null + ]); + $table->addColumn('tags', 'string', [ + 'limit' => 255, + 'null' => true, + 'default' => null + ]); + $table->addColumn('checksum', 'string', [ + 'limit' => 32, + 'null' => true, + 'default' => null + ]); + $table->addColumn('metadata', 'text', [ + 'null' => true, + 'default' => null + ]); + + $table->create(); + + $data = [ + [ + 'collection' => 'directus_files', + 'field' => 'preview', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ALIAS, + 'interface' => 'file-preview', + 'locked' => 1, + 'sort' => 1, + 'width' => 'full' + ], + [ + 'collection' => 'directus_files', + 'field' => 'title', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'placeholder' => 'Enter a descriptive title...', + 'iconRight' => 'title' + ]), + 'locked' => 1, + 'sort' => 2, + 'width' => 'full' + ], + [ + 'collection' => 'directus_files', + 'field' => 'tags', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ARRAY, + 'interface' => 'tags', + 'options' => json_encode([ + 'placeholder' => 'Enter a keyword then hit enter...' + ]), + 'sort' => 3, + 'width' => 'half', + 'locked' => 1 + ], + [ + 'collection' => 'directus_files', + 'field' => 'location', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'placeholder' => 'Enter a location...', + 'iconRight' => 'place' + ]), + 'sort' => 4, + 'width' => 'half', + 'locked' => 1 + ], + [ + 'collection' => 'directus_files', + 'field' => 'description', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'wysiwyg', + 'options' => json_encode([ + 'toolbar' => ['bold','italic','underline','link','code'] + ]), + 'sort' => 5, + 'width' => 'full', + 'locked' => 1 + ], + [ + 'collection' => 'directus_files', + 'field' => 'filename_download', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'options' => json_encode([ + 'monospace' => true, + 'iconRight' => 'get_app' + ]), + 'sort' => 6, + 'width' => 'full' + ], + [ + 'collection' => 'directus_files', + 'field' => 'filename_disk', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'placeholder' => 'Enter a unique file name...', + 'iconRight' => 'insert_drive_file' + ]), + 'locked' => 1, + 'sort' => 7, + 'width' => 'full' + ], + [ + 'collection' => 'directus_files', + 'field' => 'private_hash', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface'=> 'slug', + 'width' => 'half', + 'locked' => 1, + 'sort' => 8, + 'options' => json_encode([ + 'iconRight' => 'lock' + ]) + ], + [ + 'collection' => 'directus_files', + 'field' => 'checksum', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'readonly' => 1, + 'sort' => 9, + 'width' => 'half', + 'options' => json_encode([ + 'iconRight' => 'check', + 'monospace' => true + ]) + ], + [ + 'collection' => 'directus_files', + 'field' => 'uploaded_on', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_DATETIME, + 'interface' => 'datetime', + 'options' => json_encode([ + 'iconRight' => 'today' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 10, + 'width' => 'half', + 'required' => 1 + ], + [ + 'collection' => 'directus_files', + 'field' => 'uploaded_by', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_USER_CREATED, + 'interface' => 'user-created', + 'locked' => 1, + 'readonly' => 1, + 'sort' => 11, + 'width' => 'half', + 'required' => 1 + ], + [ + 'collection' => 'directus_files', + 'field' => 'width', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'numeric', + 'options' => json_encode([ + 'iconRight' => 'straighten' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 12, + 'width' => 'half' + ], + [ + 'collection' => 'directus_files', + 'field' => 'height', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'numeric', + 'options' => json_encode([ + 'iconRight' => 'straighten' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 13, + 'width' => 'half' + ], + [ + 'collection' => 'directus_files', + 'field' => 'duration', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'numeric', + 'options' => json_encode([ + 'iconRight' => 'timer' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 14, + 'width' => 'half' + ], + [ + 'collection' => 'directus_files', + 'field' => 'filesize', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'file-size', + 'options' => json_encode([ + 'iconRight' => 'storage' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 15, + 'width' => 'half' + ], + [ + 'collection' => 'directus_files', + 'field' => 'metadata', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'key-value', + 'locked' => 1, + 'sort' => 15, + 'width' => 'full', + 'options' => json_encode([ + 'keyInterface' => 'text-input', + 'keyDataType' => 'string', + 'keyOptions' => [ + 'monospace' => true, + 'placeholder' => 'Key' + ], + 'valueInterface' => 'text-input', + 'valueDataType' => 'string', + 'valueOptions' => [ + 'monospace' => true, + 'placeholder' => 'Value' + ] + ]) + ], + [ + 'collection' => 'directus_files', + 'field' => 'data', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ALIAS, + 'interface' => 'file', + 'locked' => 1, + 'hidden_detail' => 1 + ], + [ + 'collection' => 'directus_files', + 'field' => 'id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'primary-key', + 'locked' => 1, + 'required' => 1, + 'hidden_detail' => 1 + ], + [ + 'collection' => 'directus_files', + 'field' => 'type', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'readonly' => 1, + 'hidden_detail' => 1 + ], + [ + 'collection' => 'directus_files', + 'field' => 'charset', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'readonly' => 1, + 'hidden_detail' => 1, + 'hidden_browse' => 1 + ], + [ + 'collection' => 'directus_files', + 'field' => 'embed', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'readonly' => 1, + 'hidden_detail' => 1 + ], + [ + 'collection' => 'directus_files', + 'field' => 'folder', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, + 'interface' => 'many-to-one', + 'locked' => 1, + 'hidden_detail' => 1 + ], + [ + 'collection' => 'directus_files', + 'field' => 'storage', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'hidden_detail' => 1, + 'hidden_browse' => 1 + ] + ]; + + foreach($data as $value){ + if(!$this->checkFieldExist($value['collection'], $value['field'])){ + $fileds = $this->table('directus_fields'); + $fileds->insert($value)->save(); + } + } + } + + public function checkFieldExist($collection,$field){ + $checkSql = sprintf('SELECT 1 FROM `directus_fields` WHERE `collection` = "%s" AND `field` = "%s";', $collection, $field); + return $this->query($checkSql)->fetch(); + } +} diff --git a/migrations/install/20180220023213_create_folders_table.php b/migrations/install/20180220023213_create_folders_table.php new file mode 100644 index 0000000000..4c88e3baab --- /dev/null +++ b/migrations/install/20180220023213_create_folders_table.php @@ -0,0 +1,69 @@ +table('directus_folders', ['signed' => false]); + + $table->addColumn('name', 'string', [ + 'limit' => 191, + 'null' => false, + 'encoding' => 'utf8mb4' + ]); + $table->addColumn('parent_folder', 'integer', [ + 'signed' => false, + 'null' => true, + 'default' => null + ]); + + $table->addIndex(['name', 'parent_folder'], [ + 'unique' => true, + 'name' => 'idx_name_parent_folder' + ]); + + $table->create(); + $data = [ + [ + 'collection' => 'directus_folders', + 'field' => 'id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'primary-key', + 'locked' => 1, + 'required' => 1, + 'hidden_detail' => 1 + ], + [ + 'collection' => 'directus_folders', + 'field' => 'name', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_folders', + 'field' => 'parent_folder', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, + 'interface' => 'many-to-one', + 'locked' => 1 + ], + ]; + + foreach($data as $value){ + if(!$this->checkFieldExist($value['collection'], $value['field'])){ + $fileds = $this->table('directus_fields'); + $fileds->insert($value)->save(); + } + } + } + + public function checkFieldExist($collection,$field){ + $checkSql = sprintf('SELECT 1 FROM `directus_fields` WHERE `collection` = "%s" AND `field` = "%s";', $collection, $field); + return $this->query($checkSql)->fetch(); + } +} diff --git a/migrations/install/20180220023217_create_roles_table.php b/migrations/install/20180220023217_create_roles_table.php new file mode 100644 index 0000000000..31da7712bf --- /dev/null +++ b/migrations/install/20180220023217_create_roles_table.php @@ -0,0 +1,221 @@ +table('directus_roles', ['signed' => false]); + + $table->addColumn('name', 'string', [ + 'limit' => 100, + 'null' => false + ]); + $table->addColumn('description', 'string', [ + 'limit' => 500, + 'null' => true, + 'default' => NULL + ]); + $table->addColumn('ip_whitelist', 'text', [ + 'null' => true, + 'default' => null + ]); + $table->addColumn('external_id', 'string', [ + 'limit' => 255, + 'null' => true, + 'default' => null + ]); + $table->addColumn('module_listing', 'text', [ + 'null' => true, + 'default' => null + ]); + $table->addColumn('collection_listing', 'text', [ + 'null' => true, + 'default' => null + ]); + $table->addColumn('enforce_2fa', 'boolean', [ + 'null' => true, + 'default' => false + ]); + + $table->addIndex('name', [ + 'unique' => true, + 'name' => 'idx_group_name' + ]); + + $table->addIndex('external_id', [ + 'unique' => true, + 'name' => 'idx_roles_external_id' + ]); + + $table->create(); + $data = [ + [ + 'collection' => 'directus_roles', + 'field' => 'id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'primary-key', + 'locked' => 1, + 'required' => 1, + 'hidden_detail' => 1 + ], + [ + 'collection' => 'directus_roles', + 'field' => 'external_id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'readonly' => 1, + 'hidden_detail' => 1, + 'hidden_browse' => 1 + ], + [ + 'collection' => 'directus_roles', + 'field' => 'name', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'sort' => 1, + 'width' => 'half', + 'required' => 1 + ], + [ + 'collection' => 'directus_roles', + 'field' => 'description', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'sort' => 2, + 'width' => 'half' + ], + [ + 'collection' => 'directus_roles', + 'field' => 'ip_whitelist', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ARRAY, + 'interface' => 'tags', + 'options' => json_encode([ + '' => 'Add an IP address...' + ]), + 'locked' => 1 + ], + [ + 'collection' => 'directus_roles', + 'field' => 'enforce_2fa', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1 + ], + [ + 'collection' => 'directus_roles', + 'field' => 'users', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_O2M, + 'interface' => 'one-to-many', + 'locked' => 1, + 'options' => json_encode([ + 'fields' => "first_name,last_name" + ]) + ], + [ + 'collection' => 'directus_roles', + 'field' => 'module_listing', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'repeater', + 'locked' => 1, + 'options' => '{ + "fields": [ + { + "field": "name", + "interface": "text-input", + "type": "string", + "width": "half" + }, + { + "field": "link", + "interface": "text-input", + "type": "string", + "width": "half" + }, + { + "field": "icon", + "interface": "icon", + "type": "string", + "width": "full" + } + ] + }' + ], + [ + 'collection' => 'directus_roles', + 'field' => 'collection_listing', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'repeater', + 'locked' => 1, + 'options' => '{ + "fields": [ + { + "field": "groups", + "width": "full", + "interface": "repeater", + "type": "JSON", + "options": { + "template": "{{ label }}", + "fields": [ + { + "field": "label", + "interface": "text-input", + "type": "string" + }, + { + "field": "value", + "interface": "text-input", + "type": "string" + }, + { + "field": "icon", + "width": "full", + "interface": "icon", + "type": "string" + } + ] + } + } + ] + }' + ], + ]; + + + + foreach($data as $value){ + if(!$this->checkFieldExist($value['collection'], $value['field'])){ + $fileds = $this->table('directus_fields'); + $fileds->insert($value)->save(); + } + } + + $rolesData = [ + [ + 'id' => 1, + 'name' => 'Administrator', + 'description' => 'Admins have access to all managed data within the system by default' + ], + [ + 'id' => 2, + 'name' => 'Public', + 'description' => 'Controls what API data is publicly available without authenticating' + ] + ]; + + $groups = $this->table('directus_roles'); + $groups->insert($rolesData)->save(); + } + + public function checkFieldExist($collection,$field){ + $checkSql = sprintf('SELECT 1 FROM `directus_fields` WHERE `collection` = "%s" AND `field` = "%s";', $collection, $field); + return $this->query($checkSql)->fetch(); + } +} diff --git a/migrations/install/20180220023226_create_permissions_table.php b/migrations/install/20180220023226_create_permissions_table.php new file mode 100644 index 0000000000..86c5b01dcf --- /dev/null +++ b/migrations/install/20180220023226_create_permissions_table.php @@ -0,0 +1,189 @@ +table('directus_permissions', ['signed' => false]); + + $table->addColumn('collection', 'string', [ + 'limit' => 64, + 'null' => false, + ]); + $table->addColumn('role', 'integer', [ + 'signed' => false, + 'null' => false + ]); + $table->addColumn('status', 'string', [ + 'length' => 64, + 'default' => null, + 'null' => true + ]); + $table->addColumn('create', 'string', [ + 'signed' => false, + 'null' => true, + 'default' => 'none', + 'length' => 16, + ]); + $table->addColumn('read', 'string', [ + 'signed' => false, + 'null' => true, + 'default' => 'none', + 'length' => 16, + ]); + $table->addColumn('update', 'string', [ + 'signed' => false, + 'null' => true, + 'default' => 'none', + 'length' => 16, + ]); + $table->addColumn('delete', 'string', [ + 'signed' => false, + 'null' => true, + 'default' => 'none', + 'length' => 16, + ]); + $table->addColumn('comment', 'string', [ + 'limit' => 8, + 'null' => true, + 'default' => 'none' + ]); + $table->addColumn('explain', 'string', [ + 'limit' => 8, + 'null' => true, + 'default' => 'none' + ]); + $table->addColumn('read_field_blacklist', 'string', [ + 'limit' => 1000, + 'null' => true, + 'default' => null, + 'encoding' => 'utf8' + ]); + $table->addColumn('write_field_blacklist', 'string', [ + 'limit' => 1000, + 'null' => true, + 'default' => NULL, + 'encoding' => 'utf8', + ]); + $table->addColumn('status_blacklist', 'string', [ + 'length' => 1000, + 'default' => null, + 'null' => true + ]); + + $table->create(); + $data = [ + [ + 'collection' => 'directus_permissions', + 'field' => 'id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'primary-key', + 'locked' => 1, + 'required' => 1, + 'hidden_detail' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'collection', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, + 'interface' => 'many-to-one', + 'locked' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'role', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, + 'interface' => 'many-to-one', + 'locked' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'status', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'create', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'read', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'update', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'delete', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'primary-key', + 'locked' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'comment', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'explain', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'status_blacklist', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ARRAY, + 'interface' => 'tags', + 'locked' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'read_field_blacklist', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ARRAY, + 'interface' => 'tags', + 'locked' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'write_field_blacklist', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ARRAY, + 'interface' => 'tags', + 'locked' => 1 + ], + + ]; + + foreach($data as $value){ + if(!$this->checkFieldExist($value['collection'], $value['field'])){ + $fileds = $this->table('directus_fields'); + $fileds->insert($value)->save(); + } + } + } + + public function checkFieldExist($collection,$field){ + $checkSql = sprintf('SELECT 1 FROM `directus_fields` WHERE `collection` = "%s" AND `field` = "%s";', $collection, $field); + return $this->query($checkSql)->fetch(); + } +} diff --git a/migrations/install/20180220023232_create_relations_table.php b/migrations/install/20180220023232_create_relations_table.php new file mode 100644 index 0000000000..d8c6cb534a --- /dev/null +++ b/migrations/install/20180220023232_create_relations_table.php @@ -0,0 +1,158 @@ +table('directus_relations', ['signed' => false]); + + $table->addColumn('collection_many', 'string', [ + 'limit' => 64, + 'null' => false + ]); + $table->addColumn('field_many', 'string', [ + 'limit' => 45, + 'null' => false + ]); + $table->addColumn('collection_one', 'string', [ + 'limit' => 64, + 'null' => true + ]); + $table->addColumn('field_one', 'string', [ + 'limit' => 64, + 'null' => true + ]); + $table->addColumn('junction_field', 'string', [ + 'limit' => 64, + 'null' => true + ]); + + $table->create(); + + $data = [ + [ + 'collection' => 'directus_relations', + 'field' => 'id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'primary-key', + 'locked' => 1 + ], + [ + 'collection' => 'directus_relations', + 'field' => 'collection_many', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'collections', + 'locked' => 1 + ], + [ + 'collection' => 'directus_relations', + 'field' => 'field_many', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_relations', + 'field' => 'collection_one', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'collections', + 'locked' => 1 + ], + [ + 'collection' => 'directus_relations', + 'field' => 'field_one', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_relations', + 'field' => 'junction_field', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + ]; + + foreach($data as $value){ + if(!$this->checkFieldExist($value['collection'], $value['field'])){ + $fileds = $this->table('directus_fields'); + $fileds->insert($value)->save(); + } + } + + //Insert into relations table + $relationsData = [ + [ + 'collection_many' => 'directus_activity', + 'field_many' => 'action_by', + 'collection_one' => 'directus_users' + ], + [ + 'collection_many' => 'directus_collections_presets', + 'field_many' => 'user', + 'collection_one' => 'directus_users' + ], + [ + 'collection_many' => 'directus_collections_presets', + 'field_many' => 'group', + 'collection_one' => 'directus_groups' + ], + [ + 'collection_many' => 'directus_fields', + 'field_many' => 'collection', + 'collection_one' => 'directus_collections', + 'field_one' => 'fields' + ], + [ + 'collection_many' => 'directus_files', + 'field_many' => 'uploaded_by', + 'collection_one' => 'directus_users' + ], + [ + 'collection_many' => 'directus_files', + 'field_many' => 'folder', + 'collection_one' => 'directus_folders' + ], + [ + 'collection_many' => 'directus_folders', + 'field_many' => 'parent_folder', + 'collection_one' => 'directus_folders' + ], + [ + 'collection_many' => 'directus_permissions', + 'field_many' => 'group', + 'collection_one' => 'directus_groups' + ], + [ + 'collection_many' => 'directus_revisions', + 'field_many' => 'activity', + 'collection_one' => 'directus_activity' + ], + [ + 'collection_many' => 'directus_users', + 'field_many' => 'role', + 'collection_one' => 'directus_roles', + 'field_one' => 'users' + ], + [ + 'collection_many' => 'directus_users', + 'field_many' => 'avatar', + 'collection_one' => 'directus_files' + ] + ]; + + $files = $this->table('directus_relations'); + $files->insert($relationsData)->save(); + } + + public function checkFieldExist($collection,$field){ + $checkSql = sprintf('SELECT 1 FROM `directus_fields` WHERE `collection` = "%s" AND `field` = "%s";', $collection, $field); + return $this->query($checkSql)->fetch(); + } +} diff --git a/migrations/install/20180220023238_create_revisions_table.php b/migrations/install/20180220023238_create_revisions_table.php new file mode 100644 index 0000000000..34e51fd73d --- /dev/null +++ b/migrations/install/20180220023238_create_revisions_table.php @@ -0,0 +1,127 @@ +table('directus_revisions', ['signed' => false]); + + $table->addColumn('activity', 'integer', [ + 'null' => false, + 'signed' => false + ]); + $table->addColumn('collection', 'string', [ + 'limit' => 64, + 'null' => false + ]); + $table->addColumn('item', 'string', [ + 'limit' => 255 + ]); + $table->addColumn('data', 'text', [ + 'limit' => 4294967295 + ]); + $table->addColumn('delta', 'text', [ + 'limit' => 4294967295, + 'null' => true + ]); + $table->addColumn('parent_collection', 'string', [ + 'limit' => 64, + 'null' => true + ]); + $table->addColumn('parent_item', 'string', [ + 'limit' => 255, + 'null' => true + ]); + $table->addColumn('parent_changed', 'boolean', [ + 'signed' => false, + 'default' => false, + 'null' => true + ]); + + $table->create(); + + + $data = [ + [ + 'collection' => 'directus_revisions', + 'field' => 'id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'primary-key', + 'locked' => 1 + ], + [ + 'collection' => 'directus_revisions', + 'field' => 'activity', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, + 'interface' => 'many-to-one', + 'locked' => 1 + ], + [ + 'collection' => 'directus_revisions', + 'field' => 'collection', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, + 'interface' => 'many-to-one', + 'locked' => 1 + ], + [ + 'collection' => 'directus_revisions', + 'field' => 'item', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_revisions', + 'field' => 'data', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'json', + 'locked' => 1 + ], + [ + 'collection' => 'directus_revisions', + 'field' => 'delta', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'json', + 'locked' => 1 + ], + [ + 'collection' => 'directus_revisions', + 'field' => 'parent_item', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_revisions', + 'field' => 'parent_collection', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'collections', + 'locked' => 1 + ], + [ + 'collection' => 'directus_revisions', + 'field' => 'parent_changed', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1 + ], + ]; + + foreach($data as $value){ + if(!$this->checkFieldExist($value['collection'], $value['field'])){ + $fileds = $this->table('directus_fields'); + $fileds->insert($value)->save(); + } + } + } + + public function checkFieldExist($collection,$field){ + $checkSql = sprintf('SELECT 1 FROM `directus_fields` WHERE `collection` = "%s" AND `field` = "%s";', $collection, $field); + return $this->query($checkSql)->fetch(); + } +} diff --git a/migrations/install/20180220023243_create_settings_table.php b/migrations/install/20180220023243_create_settings_table.php new file mode 100644 index 0000000000..ab02f55ea1 --- /dev/null +++ b/migrations/install/20180220023243_create_settings_table.php @@ -0,0 +1,467 @@ +table('directus_settings', ['signed' => false]); + + $table->addColumn('key', 'string', [ + 'limit' => 64, + 'null' => false + ]); + $table->addColumn('value', 'text', [ + 'default' => null + ]); + + $table->addIndex(['key'], [ + 'unique' => true, + 'name' => 'idx_key' + ]); + + $table->create(); + + $data = [ + [ + 'collection' => 'directus_settings', + 'field' => 'project_name', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'title' + ]), + 'locked' => 1, + 'required' => 1, + 'width' => 'half', + 'note' => 'Logo in the top-left of the App (40x40)', + 'sort' => 1 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'project_url', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'link' + ]), + 'locked' => 1, + 'width' => 'half', + 'note' => 'External link for the App\'s top-left logo', + 'sort' => 2 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'project_logo', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_FILE, + 'interface' => 'file', + 'locked' => 1, + 'width' => 'half', + 'note' => 'A 40x40 brand logo, ideally a white SVG/PNG', + 'sort' => 3 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'project_color', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'color', + 'locked' => 1, + 'width' => 'half', + 'note' => 'Color for login background and App\'s logo', + 'sort' => 4 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'project_foreground', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_FILE, + 'interface' => 'file', + 'locked' => 1, + 'width' => 'half', + 'note' => 'Centered image (eg: logo) for the login page', + 'sort' => 5 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'project_background', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_FILE, + 'interface' => 'file', + 'locked' => 1, + 'width' => 'half', + 'note' => 'Full-screen background for the login page', + 'sort' => 6 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'default_locale', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'language', + 'locked' => 1, + 'width' => 'half', + 'note' => 'Default locale for Directus Users', + 'sort' => 7, + 'options' => json_encode([ + 'limit' => true + ]) + ], + [ + 'collection' => 'directus_settings', + 'field' => 'telemetry', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1, + 'width' => 'half', + 'note' => 'Learn More', + 'sort' => 8 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'data_divider', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ALIAS, + 'interface' => 'divider', + 'options' => json_encode([ + 'style' => 'large', + 'title' => 'Data', + 'hr' => true + ]), + 'locked' => 1, + 'width' => 'full', + 'hidden_browse' => 1, + 'sort' => 10 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'default_limit', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'numeric', + 'options' => json_encode([ + 'iconRight' => 'keyboard_tab' + ]), + 'locked' => 1, + 'required' => 1, + 'width' => 'half', + 'note' => 'Default item count in API and App responses', + 'sort' => 11 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'sort_null_last', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1, + 'note' => 'NULL values are sorted last', + 'width' => 'half', + 'sort' => 12 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'security_divider', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ALIAS, + 'interface' => 'divider', + 'options' => json_encode([ + 'style' => 'large', + 'title' => 'Security', + 'hr' => true + ]), + 'locked' => 1, + 'hidden_browse' => 1, + 'width' => 'full', + 'sort' => 20 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'auto_sign_out', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'numeric', + 'options' => json_encode([ + 'iconRight' => 'timer' + ]), + 'locked' => 1, + 'required' => 1, + 'width' => 'half', + 'note' => 'Minutes before idle users are signed out', + 'sort' => 22 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'login_attempts_allowed', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'numeric', + 'options' => json_encode([ + 'iconRight' => 'lock' + ]), + 'locked' => 1, + 'width' => 'half', + 'note' => 'Failed login attempts before suspending users', + 'sort' => 23 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'password_policy', + 'type' => 'string', + 'note' => 'Weak: Minimum length 8; Strong: 1 small-case letter, 1 capital letter, 1 digit, 1 special character and the length should be minimum 8', + 'interface' => 'dropdown', + 'options' => json_encode([ + 'choices' => [ + '' => 'None', + '/^.{8,}$/' => 'Weak', + '/(?=^.{8,}$)(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()_+}{\';\'?>.<,])(?!.*\s).*$/' => 'Strong' + ] + ]), + 'sort' => 24, + 'locked' => 1, + 'width' => 'half' + ], + [ + 'collection' => 'directus_settings', + 'field' => 'files_divider', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ALIAS, + 'interface' => 'divider', + 'options' => json_encode([ + 'style' => 'large', + 'title' => 'Files & Thumbnails', + 'hr' => true + ]), + 'locked' => 1, + 'hidden_browse' => 1, + 'width' => 'full', + 'sort' => 30 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'file_naming', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'dropdown', + 'locked' => 1, + 'width' => 'half', + 'note' => 'File-system naming convention for uploads', + 'sort' => 31, + 'options' => json_encode([ + 'choices' => [ + 'uuid' => 'UUID (Obfuscated)', + 'file_name' => 'File Name (Readable)' + ] + ]) + ], + [ + 'collection' => 'directus_settings', + 'field' => 'file_max_size', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'placeholder' => 'eg: 4MB', + 'iconRight' => 'storage' + ]), + 'locked' => 1, + 'width' => 'half', + 'sort' => 32 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'file_mimetype_whitelist', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ARRAY, + 'interface' => 'tags', + 'options' => json_encode([ + 'placeholder' => 'Enter a file mimetype then hit enter (eg: image/jpeg)' + ]), + 'locked' => 1, + 'width' => 'full', + 'sort' => 33 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'asset_whitelist', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'repeater', + 'width' => 'full', + 'note' => 'Defines how the thumbnail will be generated based on the requested params.', + 'sort' => 34, + 'options' => json_encode([ + 'template' => '{{key}}', + 'fields' => [ + [ + 'field' => 'key', + 'interface' => 'slug', + 'width' => 'half', + 'type' => 'string', + 'required' => true + ], + [ + 'field' => 'fit', + 'interface' => 'dropdown', + 'width' => 'half', + 'type' => 'string', + 'options' => [ + 'choices' => [ + 'crop' => 'Crop (forces exact size)', + 'contain' => 'Contain (preserve aspect ratio)' + ] + ], + 'required' => true + ], + [ + 'field' => 'width', + 'interface' => 'numeric', + 'width' => 'half', + 'type' => 'integer', + 'required' => true + ], + [ + 'field' => 'height', + 'interface' => 'numeric', + 'width' => 'half', + 'type' => 'integer', + 'required' => true + ], + [ + 'field' => 'quality', + 'interface' => 'slider', + 'width' => 'full', + 'type' => 'integer', + 'default' => 80, + 'options' => [ + 'min' => 0, + 'max' => 100, + 'step' => 1 + ], + 'required' => true + ] + ] + ]) + ], + [ + 'collection' => 'directus_settings', + 'field' => 'asset_whitelist_system', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'json', + 'readonly' => 1, + 'width' => 'half', + 'hidden_browse' => 1, + 'hidden_detail' => 1, + 'sort' => 35 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'youtube_api_key', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'videocam' + ]), + 'locked' => 1, + 'width' => 'full', + 'note' => 'Allows fetching more YouTube Embed info', + 'sort' => 36 + ], + ]; + + foreach($data as $value){ + if(!$this->checkFieldExist($value['collection'], $value['field'])){ + $fileds = $this->table('directus_fields'); + $fileds->insert($value)->save(); + } + } + + // Insert into settings table + $data = [ + [ + 'key' => 'project_url', + 'value' => '' + ], + [ + 'key' => 'project_logo', + 'value' => '' + ], + [ + 'key' => 'project_color', + 'value' => '#13181a', + ], + [ + 'key' => 'project_foreground', + 'value' => '', + ], + [ + 'key' => 'project_background', + 'value' => '', + ], + [ + 'key' => 'default_locale', + 'value' => 'en-US', + ], + [ + 'key' => 'telemetry', + 'value' => '1', + ], + [ + 'key' => 'default_limit', + 'value' => '200' + ], + [ + 'key' => 'sort_null_last', + 'value' => '1' + ], + [ + 'key' => 'password_policy', + 'value' => '' + ], + [ + 'key' => 'auto_sign_out', + 'value' => '10080' + ], + [ + 'key' => 'login_attempts_allowed', + 'value' => '10' + ], + [ + 'key' => 'trusted_proxies', + 'value' => '' + ], + [ + 'key' => 'file_max_size', + 'value' => '100MB' + ], + [ + 'key' => 'file_mimetype_whitelist', + 'value' => '' + ], + [ + 'key' => 'file_naming', + 'value' => 'uuid' + ], + [ + 'key' => 'youtube_api_key', + 'value' => '' + ], + [ + 'key' => 'asset_whitelist_system', + 'value' => json_encode([ + [ + "key" => "card", + "width" => 200, + "height" => 200, + "fit" => "crop", + "quality" => 80 + ], + [ + "key" => "avatar", + "width" => 100, + "height" => 100, + "fit" => "crop", + "quality" => 80 + ] + ]) + ] + ]; + + $groups = $this->table('directus_settings'); + $groups->insert($data)->save(); + } + + public function checkFieldExist($collection,$field){ + $checkSql = sprintf('SELECT 1 FROM `directus_fields` WHERE `collection` = "%s" AND `field` = "%s";', $collection, $field); + return $this->query($checkSql)->fetch(); + } +} diff --git a/migrations/install/20180220023248_create_users_table.php b/migrations/install/20180220023248_create_users_table.php new file mode 100644 index 0000000000..6678c5b994 --- /dev/null +++ b/migrations/install/20180220023248_create_users_table.php @@ -0,0 +1,551 @@ +table('directus_users', ['signed' => false]); + + $table->addColumn('status', 'string', [ + 'limit' => 16, + 'default' => \Directus\Database\TableGateway\DirectusUsersTableGateway::STATUS_DRAFT + ]); + $table->addColumn('role', 'integer', [ + 'null' => true, + 'default' => null + ]); + $table->addColumn('first_name', 'string', [ + 'limit' => 50, + 'null' => true, + 'default' => null + ]); + $table->addColumn('last_name', 'string', [ + 'limit' => 50, + 'null' => true, + 'default' => null + ]); + $table->addColumn('email', 'string', [ + 'limit' => 128, + 'null' => false + ]); + $table->addColumn('password', 'string', [ + 'limit' => 255, + 'encoding' => 'utf8', + 'null' => true, + 'default' => null + ]); + $table->addColumn('token', 'string', [ + 'limit' => 255, + 'encoding' => 'utf8', + 'null' => true, + 'default' => null + ]); + $table->addColumn('timezone', 'string', [ + 'limit' => 32, + 'default' => date_default_timezone_get(), + ]); + $table->addColumn('locale', 'string', [ + 'limit' => 8, + 'null' => true, + 'default' => null + ]); + $table->addColumn('locale_options', 'text', [ + 'null' => true, + 'default' => null + ]); + $table->addColumn('avatar', 'integer', [ + 'signed' => false, + 'limit' => 11, + 'null' => true, + 'default' => null + ]); + $table->addColumn('company', 'string', [ + 'limit' => 191, + 'null' => true, + 'default' => null + ]); + $table->addColumn('title', 'string', [ + 'limit' => 191, + 'null' => true, + 'default' => null + ]); + $table->addColumn('email_notifications', 'integer', [ + 'limit' => 1, + 'default' => 1 + ]); + $table->addColumn('last_access_on', 'datetime', [ + 'null' => true, + 'default' => null + ]); + $table->addColumn('last_page', 'string', [ + 'limit' => 192, + 'null' => true, + 'default' => null + ]); + $table->addColumn('external_id', 'string', [ + 'limit' => 255, + 'null' => true, + 'default' => null + ]); + $table->addColumn('theme', 'string', [ + 'limit' => 100, + 'encoding' => 'utf8', + 'null' => true, + 'default' => 'auto' + ]); + $table->addColumn('2fa_secret', 'string', [ + 'limit' => 100, + 'encoding' => 'utf8', + 'null' => true, + 'default' => null + ]); + + $table->addIndex('email', [ + 'unique' => true, + 'name' => 'idx_users_email' + ]); + + $table->addIndex('token', [ + 'unique' => true, + 'name' => 'idx_users_token' + ]); + + $table->addIndex('external_id', [ + 'unique' => true, + 'name' => 'idx_users_external_id' + ]); + + $table->create(); + + $data = [ + [ + 'collection' => 'directus_users', + 'field' => 'id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'primary-key', + 'locked' => 1, + 'required' => 1, + 'hidden_detail' => 1, + 'sort' => 1 + ], + [ + 'collection' => 'directus_users', + 'field' => 'status', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STATUS, + 'interface' => 'status', + 'options' => json_encode([ + 'status_mapping' => [ + 'draft' => [ + 'name' => 'Draft', + 'text_color' => 'white', + 'background_color' => 'light-gray', + 'listing_subdued' => false, + 'listing_badge' => true, + 'soft_delete' => false, + ], + 'invited' => [ + 'name' => 'Invited', + 'text_color' => 'white', + 'background_color' => 'light-gray', + 'listing_subdued' => false, + 'listing_badge' => true, + 'soft_delete' => false, + ], + 'active' => [ + 'name' => 'Active', + 'text_color' => 'white', + 'background_color' => 'success', + 'listing_subdued' => false, + 'listing_badge' => false, + 'soft_delete' => false, + ], + 'suspended' => [ + 'name' => 'Suspended', + 'text_color' => 'white', + 'background_color' => 'light-gray', + 'listing_subdued' => false, + 'listing_badge' => true, + 'soft_delete' => false, + ], + 'deleted' => [ + 'name' => 'Deleted', + 'text_color' => 'white', + 'background_color' => 'danger', + 'listing_subdued' => false, + 'listing_badge' => true, + 'soft_delete' => true, + ] + ] + ]), + 'locked' => 1, + 'sort' => 2, + 'required' => 1 + ], + [ + 'collection' => 'directus_users', + 'field' => 'first_name', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'account_circle' + ]), + 'locked' => 1, + 'required' => 1, + 'sort' => 3, + 'width' => 'half' + ], + [ + 'collection' => 'directus_users', + 'field' => 'last_name', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'account_circle' + ]), + 'locked' => 1, + 'required' => 1, + 'sort' => 4, + 'width' => 'half' + ], + [ + 'collection' => 'directus_users', + 'field' => 'email', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'alternate_email' + ]), + 'locked' => 1, + 'validation' => '$email', + 'required' => 1, + 'sort' => 5, + 'width' => 'half' + ], + [ + 'collection' => 'directus_users', + 'field' => 'email_notifications', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1, + 'sort' => 6, + 'width' => 'half' + ], + [ + 'collection' => 'directus_users', + 'field' => 'password', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_HASH, + 'interface' => 'password', + 'locked' => 1, + 'required' => 1, + 'sort' => 7, + 'width' => 'half' + ], + [ + 'collection' => 'directus_users', + 'field' => 'role', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, + 'interface' => 'user-roles', + 'locked' => 1, + 'sort' => 8, + 'width' => 'half', + 'required' => 1 + ], + [ + 'collection' => 'directus_users', + 'field' => 'company', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'location_city' + ]), + 'sort' => 9, + 'width' => 'half' + ], + [ + 'collection' => 'directus_users', + 'field' => 'title', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'text_fields' + ]), + 'sort' => 10, + 'width' => 'half' + ], + [ + 'collection' => 'directus_users', + 'field' => 'timezone', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'dropdown', + 'options' => json_encode([ + 'choices' => [ + 'Pacific/Midway' => '(UTC-11:00) Midway Island', + 'Pacific/Samoa' => '(UTC-11:00) Samoa', + 'Pacific/Honolulu' => '(UTC-10:00) Hawaii', + 'US/Alaska' => '(UTC-09:00) Alaska', + 'America/Los_Angeles' => '(UTC-08:00) Pacific Time (US & Canada)', + 'America/Tijuana' => '(UTC-08:00) Tijuana', + 'US/Arizona' => '(UTC-07:00) Arizona', + 'America/Chihuahua' => '(UTC-07:00) Chihuahua', + 'America/Mexico/La_Paz' => '(UTC-07:00) La Paz', + 'America/Mazatlan' => '(UTC-07:00) Mazatlan', + 'US/Mountain' => '(UTC-07:00) Mountain Time (US & Canada)', + 'America/Managua' => '(UTC-06:00) Central America', + 'US/Central' => '(UTC-06:00) Central Time (US & Canada)', + 'America/Guadalajara' => '(UTC-06:00) Guadalajara', + 'America/Mexico_City' => '(UTC-06:00) Mexico City', + 'America/Monterrey' => '(UTC-06:00) Monterrey', + 'Canada/Saskatchewan' => '(UTC-06:00) Saskatchewan', + 'America/Bogota' => '(UTC-05:00) Bogota', + 'US/Eastern' => '(UTC-05:00) Eastern Time (US & Canada)', + 'US/East-Indiana' => '(UTC-05:00) Indiana (East)', + 'America/Lima' => '(UTC-05:00) Lima', + 'America/Quito' => '(UTC-05:00) Quito', + 'Canada/Atlantic' => '(UTC-04:00) Atlantic Time (Canada)', + 'America/New_York' => '(UTC-04:00) New York', + 'America/Caracas' => '(UTC-04:30) Caracas', + 'America/La_Paz' => '(UTC-04:00) La Paz', + 'America/Santiago' => '(UTC-04:00) Santiago', + 'America/Santo_Domingo' => '(UTC-04:00) Santo Domingo', + 'Canada/Newfoundland' => '(UTC-03:30) Newfoundland', + 'America/Sao_Paulo' => '(UTC-03:00) Brasilia', + 'America/Argentina/Buenos_Aires' => '(UTC-03:00) Buenos Aires', + 'America/Argentina/GeorgeTown' => '(UTC-03:00) Georgetown', + 'America/Godthab' => '(UTC-03:00) Greenland', + 'America/Noronha' => '(UTC-02:00) Mid-Atlantic', + 'Atlantic/Azores' => '(UTC-01:00) Azores', + 'Atlantic/Cape_Verde' => '(UTC-01:00) Cape Verde Is.', + 'Africa/Casablanca' => '(UTC+00:00) Casablanca', + 'Europe/Edinburgh' => '(UTC+00:00) Edinburgh', + 'Etc/Greenwich' => '(UTC+00:00) Greenwich Mean Time : Dublin', + 'Europe/Lisbon' => '(UTC+00:00) Lisbon', + 'Europe/London' => '(UTC+00:00) London', + 'Africa/Monrovia' => '(UTC+00:00) Monrovia', + 'UTC' => '(UTC+00:00) UTC', + 'Europe/Amsterdam' => '(UTC+01:00) Amsterdam', + 'Europe/Belgrade' => '(UTC+01:00) Belgrade', + 'Europe/Berlin' => '(UTC+01:00) Berlin', + 'Europe/Bern' => '(UTC+01:00) Bern', + 'Europe/Bratislava' => '(UTC+01:00) Bratislava', + 'Europe/Brussels' => '(UTC+01:00) Brussels', + 'Europe/Budapest' => '(UTC+01:00) Budapest', + 'Europe/Copenhagen' => '(UTC+01:00) Copenhagen', + 'Europe/Ljubljana' => '(UTC+01:00) Ljubljana', + 'Europe/Madrid' => '(UTC+01:00) Madrid', + 'Europe/Paris' => '(UTC+01:00) Paris', + 'Europe/Prague' => '(UTC+01:00) Prague', + 'Europe/Rome' => '(UTC+01:00) Rome', + 'Europe/Sarajevo' => '(UTC+01:00) Sarajevo', + 'Europe/Skopje' => '(UTC+01:00) Skopje', + 'Europe/Stockholm' => '(UTC+01:00) Stockholm', + 'Europe/Vienna' => '(UTC+01:00) Vienna', + 'Europe/Warsaw' => '(UTC+01:00) Warsaw', + 'Africa/Lagos' => '(UTC+01:00) West Central Africa', + 'Europe/Zagreb' => '(UTC+01:00) Zagreb', + 'Europe/Athens' => '(UTC+02:00) Athens', + 'Europe/Bucharest' => '(UTC+02:00) Bucharest', + 'Africa/Cairo' => '(UTC+02:00) Cairo', + 'Africa/Harare' => '(UTC+02:00) Harare', + 'Europe/Helsinki' => '(UTC+02:00) Helsinki', + 'Europe/Istanbul' => '(UTC+02:00) Istanbul', + 'Asia/Jerusalem' => '(UTC+02:00) Jerusalem', + 'Europe/Kyiv' => '(UTC+02:00) Kyiv', + 'Africa/Johannesburg' => '(UTC+02:00) Pretoria', + 'Europe/Riga' => '(UTC+02:00) Riga', + 'Europe/Sofia' => '(UTC+02:00) Sofia', + 'Europe/Tallinn' => '(UTC+02:00) Tallinn', + 'Europe/Vilnius' => '(UTC+02:00) Vilnius', + 'Asia/Baghdad' => '(UTC+03:00) Baghdad', + 'Asia/Kuwait' => '(UTC+03:00) Kuwait', + 'Europe/Minsk' => '(UTC+03:00) Minsk', + 'Africa/Nairobi' => '(UTC+03:00) Nairobi', + 'Asia/Riyadh' => '(UTC+03:00) Riyadh', + 'Europe/Volgograd' => '(UTC+03:00) Volgograd', + 'Asia/Tehran' => '(UTC+03:30) Tehran', + 'Asia/Abu_Dhabi' => '(UTC+04:00) Abu Dhabi', + 'Asia/Baku' => '(UTC+04:00) Baku', + 'Europe/Moscow' => '(UTC+04:00) Moscow', + 'Asia/Muscat' => '(UTC+04:00) Muscat', + 'Europe/St_Petersburg' => '(UTC+04:00) St. Petersburg', + 'Asia/Tbilisi' => '(UTC+04:00) Tbilisi', + 'Asia/Yerevan' => '(UTC+04:00) Yerevan', + 'Asia/Kabul' => '(UTC+04:30) Kabul', + 'Asia/Islamabad' => '(UTC+05:00) Islamabad', + 'Asia/Karachi' => '(UTC+05:00) Karachi', + 'Asia/Tashkent' => '(UTC+05:00) Tashkent', + 'Asia/Calcutta' => '(UTC+05:30) Chennai', + 'Asia/Kolkata' => '(UTC+05:30) Kolkata', + 'Asia/Mumbai' => '(UTC+05:30) Mumbai', + 'Asia/New_Delhi' => '(UTC+05:30) New Delhi', + 'Asia/Sri_Jayawardenepura' => '(UTC+05:30) Sri Jayawardenepura', + 'Asia/Katmandu' => '(UTC+05:45) Kathmandu', + 'Asia/Almaty' => '(UTC+06:00) Almaty', + 'Asia/Astana' => '(UTC+06:00) Astana', + 'Asia/Dhaka' => '(UTC+06:00) Dhaka', + 'Asia/Yekaterinburg' => '(UTC+06:00) Ekaterinburg', + 'Asia/Rangoon' => '(UTC+06:30) Rangoon', + 'Asia/Bangkok' => '(UTC+07:00) Bangkok', + 'Asia/Hanoi' => '(UTC+07:00) Hanoi', + 'Asia/Jakarta' => '(UTC+07:00) Jakarta', + 'Asia/Novosibirsk' => '(UTC+07:00) Novosibirsk', + 'Asia/Beijing' => '(UTC+08:00) Beijing', + 'Asia/Chongqing' => '(UTC+08:00) Chongqing', + 'Asia/Hong_Kong' => '(UTC+08:00) Hong Kong', + 'Asia/Krasnoyarsk' => '(UTC+08:00) Krasnoyarsk', + 'Asia/Kuala_Lumpur' => '(UTC+08:00) Kuala Lumpur', + 'Australia/Perth' => '(UTC+08:00) Perth', + 'Asia/Singapore' => '(UTC+08:00) Singapore', + 'Asia/Taipei' => '(UTC+08:00) Taipei', + 'Asia/Ulan_Bator' => '(UTC+08:00) Ulaan Bataar', + 'Asia/Urumqi' => '(UTC+08:00) Urumqi', + 'Asia/Irkutsk' => '(UTC+09:00) Irkutsk', + 'Asia/Osaka' => '(UTC+09:00) Osaka', + 'Asia/Sapporo' => '(UTC+09:00) Sapporo', + 'Asia/Seoul' => '(UTC+09:00) Seoul', + 'Asia/Tokyo' => '(UTC+09:00) Tokyo', + 'Australia/Adelaide' => '(UTC+09:30) Adelaide', + 'Australia/Darwin' => '(UTC+09:30) Darwin', + 'Australia/Brisbane' => '(UTC+10:00) Brisbane', + 'Australia/Canberra' => '(UTC+10:00) Canberra', + 'Pacific/Guam' => '(UTC+10:00) Guam', + 'Australia/Hobart' => '(UTC+10:00) Hobart', + 'Australia/Melbourne' => '(UTC+10:00) Melbourne', + 'Pacific/Port_Moresby' => '(UTC+10:00) Port Moresby', + 'Australia/Sydney' => '(UTC+10:00) Sydney', + 'Asia/Yakutsk' => '(UTC+10:00) Yakutsk', + 'Asia/Vladivostok' => '(UTC+11:00) Vladivostok', + 'Pacific/Auckland' => '(UTC+12:00) Auckland', + 'Pacific/Fiji' => '(UTC+12:00) Fiji', + 'Pacific/Kwajalein' => '(UTC+12:00) International Date Line West', + 'Asia/Kamchatka' => '(UTC+12:00) Kamchatka', + 'Asia/Magadan' => '(UTC+12:00) Magadan', + 'Pacific/Marshall_Is' => '(UTC+12:00) Marshall Is.', + 'Asia/New_Caledonia' => '(UTC+12:00) New Caledonia', + 'Asia/Solomon_Is' => '(UTC+12:00) Solomon Is.', + 'Pacific/Wellington' => '(UTC+12:00) Wellington', + 'Pacific/Tongatapu' => '(UTC+13:00) Nuku\'alofa' + ], + 'placeholder' => 'Choose a timezone...' + ]), + 'locked' => 1, + 'sort' => 11, + 'width' => 'half', + 'required' => 1 + ], + [ + 'collection' => 'directus_users', + 'field' => 'locale', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'language', + 'options' => json_encode([ + 'limit' => true + ]), + 'locked' => 1, + 'sort' => 12, + 'width' => 'half', + 'required' => 0 + ], + [ + 'collection' => 'directus_users', + 'field' => 'avatar', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_FILE, + 'interface' => 'file', + 'locked' => 1, + 'sort' => 13 + ], + [ + 'collection' => 'directus_users', + 'field' => 'theme', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'radio-buttons', + 'options' => json_encode([ + 'format' => true, + 'choices' => [ + 'auto' => 'Auto', + 'light' => 'Light', + 'dark' => 'Dark' + ] + ]), + 'locked' => 1, + 'readonly' => 0, + 'sort' => 14 + ], + [ + 'collection' => 'directus_users', + 'field' => '2fa_secret', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => '2fa-secret', + 'locked' => 1, + 'readonly' => 1, + 'sort' => 15 + ], + [ + 'collection' => 'directus_users', + 'field' => 'locale_options', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'json', + 'locked' => 1, + 'hidden_browse' => 1, + 'hidden_detail' => 1, + 'sort' => 16 + ], + [ + 'collection' => 'directus_users', + 'field' => 'token', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'hidden_detail' => 1, + 'hidden_browse' => 1, + 'sort' => 17 + ], + [ + 'collection' => 'directus_users', + 'field' => 'last_access_on', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_DATETIME, + 'interface' => 'datetime', + 'locked' => 1, + 'readonly' => 1, + 'hidden_detail' => 1, + 'sort' => 18 + ], + [ + 'collection' => 'directus_users', + 'field' => 'last_page', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'readonly' => 1, + 'hidden_detail' => 1, + 'hidden_browse' => 1, + 'sort' => 19 + ], + [ + 'collection' => 'directus_users', + 'field' => 'external_id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'readonly' => 1, + 'hidden_detail' => 20 + ], + ]; + + foreach($data as $value){ + if(!$this->checkFieldExist($value['collection'], $value['field'])){ + $fileds = $this->table('directus_fields'); + $fileds->insert($value)->save(); + } + } + } + + public function checkFieldExist($collection,$field){ + $checkSql = sprintf('SELECT 1 FROM `directus_fields` WHERE `collection` = "%s" AND `field` = "%s";', $collection, $field); + return $this->query($checkSql)->fetch(); + } +} diff --git a/migrations/upgrades/schemas/20190912072543_create_user_sessions.php b/migrations/install/20190912072543_create_user_sessions.php similarity index 71% rename from migrations/upgrades/schemas/20190912072543_create_user_sessions.php rename to migrations/install/20190912072543_create_user_sessions.php index affa1768df..2ba131d026 100644 --- a/migrations/upgrades/schemas/20190912072543_create_user_sessions.php +++ b/migrations/install/20190912072543_create_user_sessions.php @@ -6,25 +6,7 @@ class CreateUserSessions extends AbstractMigration { /** - * Change Method. - * - * Write your reversible migrations using this method. - * - * More information on writing migrations is available here: - * http://docs.phinx.org/en/latest/migrations.html#the-abstractmigration-class - * - * The following commands can be used in this method and Phinx will - * automatically reverse them when rolling back: - * - * createTable - * renameTable - * addColumn - * renameColumn - * addIndex - * addForeignKey - * - * Remember to call "create()" or "update()" and NOT "save()" when working - * with the Table class. + * Create User Sessions Table */ public function change() { @@ -36,6 +18,11 @@ public function change() 'default' => null ]); + $table->addColumn('token_type', 'string', [ + 'null' => true, + 'default' => null + ]); + $table->addColumn('token', 'string', [ 'limit' => 520, 'encoding' => 'utf8', @@ -60,13 +47,15 @@ public function change() 'null' => true, 'default' => null ]); - + + $table->addColumn('token_expired_at', 'datetime', [ + 'null' => true, + 'default' => null + ]); + $table->create(); - // Insert Into Directus Fields $data = [ - // User Session - // ----------------------------------------------------------------- [ 'collection' => 'directus_user_sessions', 'field' => 'id', @@ -123,15 +112,14 @@ public function change() foreach($data as $value){ if(!$this->checkFieldExist($value['collection'], $value['field'])){ - $insertSqlFormat = "INSERT INTO `directus_fields` (`collection`, `field`, `type`, `interface`, `hidden_detail`, `required`, `locked`, `options`) VALUES ('%s', '%s', '%s', '%s', '%s', '%s','%s' , '%s');"; - $insertSql = sprintf($insertSqlFormat,$value['collection'], $value['field'], $value['type'], $value['interface'], isset($value['hidden_detail']) ? $value['hidden_detail'] : 0, isset($value['required']) ? $value['required'] : 0, isset($value['locked']) ? $value['locked'] : 0, isset($value['options']) ? $value['options'] : null); - $this->execute($insertSql); + $fileds = $this->table('directus_fields'); + $fileds->insert($value)->save(); } } } + public function checkFieldExist($collection,$field){ $checkSql = sprintf('SELECT 1 FROM `directus_fields` WHERE `collection` = "%s" AND `field` = "%s";', $collection, $field); return $this->query($checkSql)->fetch(); } - } diff --git a/migrations/upgrades/schemas/20190917090849_create_web_hooks.php b/migrations/install/20190917090849_create_webhooks.php similarity index 59% rename from migrations/upgrades/schemas/20190917090849_create_web_hooks.php rename to migrations/install/20190917090849_create_webhooks.php index 374a3c28fb..e3cbfebacb 100644 --- a/migrations/upgrades/schemas/20190917090849_create_web_hooks.php +++ b/migrations/install/20190917090849_create_webhooks.php @@ -1,4 +1,3 @@ - \Directus\Api\Routes\Webhook::STATUS_INACTIVE ]); - $table->addColumn('collection', 'string', [ - 'limit' => 255, - 'null' => true, - 'default' => null - ]); - $table->addColumn('directus_action', 'string', [ + $table->addColumn('http_action', 'string', [ 'limit' => 255, 'encoding' => 'utf8', 'null' => true, @@ -56,18 +32,21 @@ public function change() 'default' => null ]); - $table->addColumn('http_action', 'string', [ + $table->addColumn('collection', 'string', [ 'limit' => 255, - 'encoding' => 'utf8', 'null' => true, 'default' => null ]); - + $table->addColumn('directus_action', 'string', [ + 'limit' => 255, + 'encoding' => 'utf8', + 'null' => true, + 'default' => null + ]); $table->create(); - // Insert Into Directus Fields $data = [ [ 'collection' => 'directus_webhooks', @@ -85,39 +64,31 @@ public function change() 'interface' => 'status', 'options' => json_encode([ 'status_mapping' => [ - 'published' => [ - 'name' => 'Published', - 'value' => 'published', + 'active' => [ + 'name' => 'Active', + 'value' => 'active', 'text_color' => 'white', - 'background_color' => 'accent', + 'background_color' => 'green', 'browse_subdued' => false, 'browse_badge' => true, 'soft_delete' => false, 'published' => true, ], - 'draft' => [ - 'name' => 'Draft', - 'value' => 'draft', + 'inactive' => [ + 'name' => 'Inactive', + 'value' => 'inactive', 'text_color' => 'white', - 'background_color' => 'blue-grey-100', + 'background_color' => 'blue-grey', 'browse_subdued' => true, 'browse_badge' => true, 'soft_delete' => false, 'published' => false, - ], - 'deleted' => [ - 'name' => 'Deleted', - 'value' => 'deleted', - 'text_color' => 'white', - 'background_color' => 'red', - 'browse_subdued' => true, - 'browse_badge' => true, - 'soft_delete' => true, - 'published' => false, ] ] ]), - 'required' => 1 + 'locked' => 1, + 'width' => 'full', + 'sort' => 1 ], [ 'collection' => 'directus_webhooks', @@ -127,17 +98,39 @@ public function change() 'required' => 1, 'options' => json_encode([ 'choices' => [ - 'get' => 'Get', - 'post' => 'Post' + 'get' => 'GET', + 'post' => 'POST' ] - ]) + ]), + 'locked' => 1, + 'width' => 'half-space', + 'sort' => 2 + ], + [ + 'collection' => 'directus_webhooks', + 'field' => 'url', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'placeholder' => 'https://example.com', + 'iconRight' => 'link' + ]), + 'required' => 1, + 'locked' => 1, + 'width' => 'full', + 'note' => '', + 'sort' => 3 ], [ 'collection' => 'directus_webhooks', 'field' => 'collection', 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, 'interface' => 'collections', - 'required' => 1 + 'required' => 1, + 'locked' => 1, + 'width' => 'half', + 'note' => '', + 'sort' => 4 ], [ 'collection' => 'directus_webhooks', @@ -147,31 +140,39 @@ public function change() 'required' => 1, 'options' => json_encode([ 'choices' => [ - 'item.create:before' => 'item.create:before', - 'item.create:after' => 'item.create:after', - 'item.update:before' => 'item.update:before', - 'item.update:after' => 'item.update:after', - 'item.delete:before' => 'item.delete:before', - 'item.delete:after' => 'item.delete:after', + 'item.create:after' => 'Create', + 'item.update:after' => 'Update', + 'item.delete:after' => 'Delete', ] - ]) + ]), + 'locked' => 1, + 'width' => 'half', + 'note' => '', + 'sort' => 5 ], [ 'collection' => 'directus_webhooks', - 'field' => 'url', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'interface' => 'text-input', - 'required' => 1 - ] - + 'field' => 'info', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ALIAS, + 'interface' => 'divider', + 'options' => json_encode([ + 'style' => 'medium', + 'title' => 'How Webhooks Work', + 'hr' => true, + 'margin' => false, + 'description' => 'When the selected action occurs for the selected collection, Directus will send an HTTP request to the above URL.' + ]), + 'locked' => 1, + 'width' => 'full', + 'hidden_browse' => 1, + 'sort' => 6 + ], ]; foreach($data as $value){ if(!$this->checkFieldExist($value['collection'], $value['field'])){ - $insertSqlFormat = "INSERT INTO `directus_fields` (`collection`, `field`, `type`, `interface`, `hidden_detail`, `required`, `locked`, `options`) VALUES ('%s', '%s', '%s', '%s', '%s', '%s','%s' , '%s');"; - - $insertSql = sprintf($insertSqlFormat,$value['collection'], $value['field'], $value['type'], $value['interface'], isset($value['hidden_detail']) ? $value['hidden_detail'] : 0, $value['required'], isset($value['locked']) ? $value['locked'] : 0, isset($value['options']) ? $value['options'] : null); - $this->execute($insertSql); + $fileds = $this->table('directus_fields'); + $fileds->insert($value)->save(); } } } diff --git a/migrations/migrations.php b/migrations/migrations.php index cb6b9a5d5f..288783c0fa 100644 --- a/migrations/migrations.php +++ b/migrations/migrations.php @@ -2,8 +2,7 @@ return [ 'paths' => [ - 'migrations' => '%%PHINX_CONFIG_DIR%%/../migrations/db/schemas', - 'seeds' => '%%PHINX_CONFIG_DIR%%/../migrations/db/seeds' + 'migrations' => '%%PHINX_CONFIG_DIR%%/../migrations/install' ], 'version_order' => 'creation', diff --git a/migrations/migrations.upgrades.php b/migrations/migrations.upgrades.php index 3b6414a7b8..ab7481401e 100644 --- a/migrations/migrations.upgrades.php +++ b/migrations/migrations.upgrades.php @@ -2,8 +2,7 @@ return [ 'paths' => [ - 'migrations' => '%%PHINX_CONFIG_DIR%%/../migrations/upgrades/schemas', - 'seeds' => '%%PHINX_CONFIG_DIR%%/../migrations/upgrades/seeds' + 'migrations' => '%%PHINX_CONFIG_DIR%%/../migrations/upgrades' ], 'version_order' => 'creation', diff --git a/migrations/upgrades/schemas/20181022175715_upgrade_070003.php b/migrations/upgrades/20181022175715_upgrade_070003.php similarity index 100% rename from migrations/upgrades/schemas/20181022175715_upgrade_070003.php rename to migrations/upgrades/20181022175715_upgrade_070003.php diff --git a/migrations/upgrades/schemas/20181102153600_timezone_choices.php b/migrations/upgrades/20181102153600_timezone_choices.php similarity index 100% rename from migrations/upgrades/schemas/20181102153600_timezone_choices.php rename to migrations/upgrades/20181102153600_timezone_choices.php diff --git a/migrations/upgrades/schemas/20181105165224_upgrade_070006.php b/migrations/upgrades/20181105165224_upgrade_070006.php similarity index 100% rename from migrations/upgrades/schemas/20181105165224_upgrade_070006.php rename to migrations/upgrades/20181105165224_upgrade_070006.php diff --git a/migrations/upgrades/schemas/20181122195602_locale_interface.php b/migrations/upgrades/20181122195602_locale_interface.php similarity index 100% rename from migrations/upgrades/schemas/20181122195602_locale_interface.php rename to migrations/upgrades/20181122195602_locale_interface.php diff --git a/migrations/upgrades/schemas/20181123171520_remove_scope.php b/migrations/upgrades/20181123171520_remove_scope.php similarity index 100% rename from migrations/upgrades/schemas/20181123171520_remove_scope.php rename to migrations/upgrades/20181123171520_remove_scope.php diff --git a/migrations/upgrades/schemas/20181210204720_add_trusted_proxies_setting_field.php b/migrations/upgrades/20181210204720_add_trusted_proxies_setting_field.php similarity index 100% rename from migrations/upgrades/schemas/20181210204720_add_trusted_proxies_setting_field.php rename to migrations/upgrades/20181210204720_add_trusted_proxies_setting_field.php diff --git a/migrations/upgrades/schemas/20181222023800_add_project_url_setting_field.php b/migrations/upgrades/20181222023800_add_project_url_setting_field.php similarity index 100% rename from migrations/upgrades/schemas/20181222023800_add_project_url_setting_field.php rename to migrations/upgrades/20181222023800_add_project_url_setting_field.php diff --git a/migrations/upgrades/schemas/20181227042755_increase_users_last_page_length.php b/migrations/upgrades/20181227042755_increase_users_last_page_length.php similarity index 100% rename from migrations/upgrades/schemas/20181227042755_increase_users_last_page_length.php rename to migrations/upgrades/20181227042755_increase_users_last_page_length.php diff --git a/migrations/upgrades/schemas/20190104155309_add_users_email_validation.php b/migrations/upgrades/20190104155309_add_users_email_validation.php similarity index 100% rename from migrations/upgrades/schemas/20190104155309_add_users_email_validation.php rename to migrations/upgrades/20190104155309_add_users_email_validation.php diff --git a/migrations/upgrades/schemas/20190111193724_add_app_url_setting_field.php b/migrations/upgrades/20190111193724_add_app_url_setting_field.php similarity index 100% rename from migrations/upgrades/schemas/20190111193724_add_app_url_setting_field.php rename to migrations/upgrades/20190111193724_add_app_url_setting_field.php diff --git a/migrations/upgrades/schemas/20190111212736_add_missing_settings_field.php b/migrations/upgrades/20190111212736_add_missing_settings_field.php similarity index 100% rename from migrations/upgrades/schemas/20190111212736_add_missing_settings_field.php rename to migrations/upgrades/20190111212736_add_missing_settings_field.php diff --git a/migrations/upgrades/schemas/20190118181424_add_roles_users_field.php b/migrations/upgrades/20190118181424_add_roles_users_field.php similarity index 100% rename from migrations/upgrades/schemas/20190118181424_add_roles_users_field.php rename to migrations/upgrades/20190118181424_add_roles_users_field.php diff --git a/migrations/upgrades/schemas/20190130215921_add_files_checksum_field.php b/migrations/upgrades/20190130215921_add_files_checksum_field.php similarity index 100% rename from migrations/upgrades/schemas/20190130215921_add_files_checksum_field.php rename to migrations/upgrades/20190130215921_add_files_checksum_field.php diff --git a/migrations/upgrades/schemas/20190318173400_add_nav_override.php b/migrations/upgrades/20190318173400_add_nav_override.php similarity index 100% rename from migrations/upgrades/schemas/20190318173400_add_nav_override.php rename to migrations/upgrades/20190318173400_add_nav_override.php diff --git a/migrations/upgrades/schemas/20190412122400_set_password_type_to_hash.php b/migrations/upgrades/20190412122400_set_password_type_to_hash.php similarity index 100% rename from migrations/upgrades/schemas/20190412122400_set_password_type_to_hash.php rename to migrations/upgrades/20190412122400_set_password_type_to_hash.php diff --git a/migrations/upgrades/schemas/20190412123000_use_file_interface.php b/migrations/upgrades/20190412123000_use_file_interface.php similarity index 100% rename from migrations/upgrades/schemas/20190412123000_use_file_interface.php rename to migrations/upgrades/20190412123000_use_file_interface.php diff --git a/migrations/upgrades/schemas/20190412145800_set_o2m_options_roles.php b/migrations/upgrades/20190412145800_set_o2m_options_roles.php similarity index 100% rename from migrations/upgrades/schemas/20190412145800_set_o2m_options_roles.php rename to migrations/upgrades/20190412145800_set_o2m_options_roles.php diff --git a/migrations/upgrades/schemas/20190415125300_set_width.php b/migrations/upgrades/20190415125300_set_width.php similarity index 100% rename from migrations/upgrades/schemas/20190415125300_set_width.php rename to migrations/upgrades/20190415125300_set_width.php diff --git a/migrations/upgrades/schemas/20190419154400_settings_fields.php b/migrations/upgrades/20190419154400_settings_fields.php similarity index 100% rename from migrations/upgrades/schemas/20190419154400_settings_fields.php rename to migrations/upgrades/20190419154400_settings_fields.php diff --git a/migrations/upgrades/schemas/20190419161200_collection_notes.php b/migrations/upgrades/20190419161200_collection_notes.php similarity index 100% rename from migrations/upgrades/schemas/20190419161200_collection_notes.php rename to migrations/upgrades/20190419161200_collection_notes.php diff --git a/migrations/upgrades/schemas/20190419173000_misc_required_fields.php b/migrations/upgrades/20190419173000_misc_required_fields.php similarity index 100% rename from migrations/upgrades/schemas/20190419173000_misc_required_fields.php rename to migrations/upgrades/20190419173000_misc_required_fields.php diff --git a/migrations/upgrades/schemas/20190422131600_use_json.php b/migrations/upgrades/20190422131600_use_json.php similarity index 95% rename from migrations/upgrades/schemas/20190422131600_use_json.php rename to migrations/upgrades/20190422131600_use_json.php index dd26ee3f69..ba2ee9d67c 100644 --- a/migrations/upgrades/schemas/20190422131600_use_json.php +++ b/migrations/upgrades/20190422131600_use_json.php @@ -15,13 +15,13 @@ public function up() ['collection' => 'directus_activity', 'interface' => 'code'] )); - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'interface' => 'json' - ], - ['collection' => 'directus_activity_seen', 'interface' => 'code'] + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + [ + 'interface' => 'json' + ], + ['collection' => 'directus_activity_seen', 'interface' => 'code'] )); $this->execute(\Directus\phinx_update( diff --git a/migrations/upgrades/schemas/20190426156200_set_nullable_value_field_settings_table.php b/migrations/upgrades/20190426156200_set_nullable_value_field_settings_table.php similarity index 100% rename from migrations/upgrades/schemas/20190426156200_set_nullable_value_field_settings_table.php rename to migrations/upgrades/20190426156200_set_nullable_value_field_settings_table.php diff --git a/migrations/upgrades/schemas/20190520094300_use_timeline.php b/migrations/upgrades/20190520094300_use_timeline.php similarity index 100% rename from migrations/upgrades/schemas/20190520094300_use_timeline.php rename to migrations/upgrades/20190520094300_use_timeline.php diff --git a/migrations/upgrades/schemas/20190614103321_add_users_2fa_secret_field.php b/migrations/upgrades/20190614103321_add_users_2fa_secret_field.php similarity index 100% rename from migrations/upgrades/schemas/20190614103321_add_users_2fa_secret_field.php rename to migrations/upgrades/20190614103321_add_users_2fa_secret_field.php diff --git a/migrations/upgrades/schemas/20190618190024_add_enforce_2fa_role_field.php b/migrations/upgrades/20190618190024_add_enforce_2fa_role_field.php similarity index 100% rename from migrations/upgrades/schemas/20190618190024_add_enforce_2fa_role_field.php rename to migrations/upgrades/20190618190024_add_enforce_2fa_role_field.php diff --git a/migrations/upgrades/schemas/20190626114228_add_file_naming_in_setting.php b/migrations/upgrades/20190626114228_add_file_naming_in_setting.php similarity index 100% rename from migrations/upgrades/schemas/20190626114228_add_file_naming_in_setting.php rename to migrations/upgrades/20190626114228_add_file_naming_in_setting.php diff --git a/migrations/upgrades/schemas/20190702092323_add_login_attempts_allowed_setting.php b/migrations/upgrades/20190702092323_add_login_attempts_allowed_setting.php similarity index 100% rename from migrations/upgrades/schemas/20190702092323_add_login_attempts_allowed_setting.php rename to migrations/upgrades/20190702092323_add_login_attempts_allowed_setting.php diff --git a/migrations/upgrades/schemas/20190704063752_update_istanbul_timezone.php b/migrations/upgrades/20190704063752_update_istanbul_timezone.php similarity index 100% rename from migrations/upgrades/schemas/20190704063752_update_istanbul_timezone.php rename to migrations/upgrades/20190704063752_update_istanbul_timezone.php diff --git a/migrations/upgrades/schemas/20190708095522_add_file_extension_setting.php b/migrations/upgrades/20190708095522_add_file_extension_setting.php similarity index 100% rename from migrations/upgrades/schemas/20190708095522_add_file_extension_setting.php rename to migrations/upgrades/20190708095522_add_file_extension_setting.php diff --git a/migrations/upgrades/schemas/20190709053719_add_file_max_size_setting.php b/migrations/upgrades/20190709053719_add_file_max_size_setting.php similarity index 100% rename from migrations/upgrades/schemas/20190709053719_add_file_max_size_setting.php rename to migrations/upgrades/20190709053719_add_file_max_size_setting.php diff --git a/migrations/upgrades/schemas/20190722110232_password_validation_setting_field.php b/migrations/upgrades/20190722110232_password_validation_setting_field.php similarity index 100% rename from migrations/upgrades/schemas/20190722110232_password_validation_setting_field.php rename to migrations/upgrades/20190722110232_password_validation_setting_field.php diff --git a/migrations/upgrades/schemas/20190726064001_update_note_for_default_limit.php b/migrations/upgrades/20190726064001_update_note_for_default_limit.php similarity index 100% rename from migrations/upgrades/schemas/20190726064001_update_note_for_default_limit.php rename to migrations/upgrades/20190726064001_update_note_for_default_limit.php diff --git a/migrations/upgrades/schemas/20190819070856_update_directus_fields_field.php b/migrations/upgrades/20190819070856_update_directus_fields_field.php similarity index 100% rename from migrations/upgrades/schemas/20190819070856_update_directus_fields_field.php rename to migrations/upgrades/20190819070856_update_directus_fields_field.php diff --git a/migrations/upgrades/20191123053252_update_directus_files_field.php b/migrations/upgrades/20191123053252_update_directus_files_field.php new file mode 100644 index 0000000000..a56bd9e845 --- /dev/null +++ b/migrations/upgrades/20191123053252_update_directus_files_field.php @@ -0,0 +1,189 @@ +table('directus_files'); + $fieldsTable = $this->table('directus_fields'); + + if(!$this->checkFieldExist('directus_files', 'checksum')){ + $fieldsTable->insert([ + 'collection' => 'directus_files', + 'field' => 'checksum', + 'type' => 'string', + 'interface' => 'text-input', + ])->save(); + } + if (!$filesTable->hasColumn('checksum')) { + $filesTable->addColumn('checksum', 'string', [ + 'limit' => 32, + 'null' => true, + 'default' => null, + 'hidden_browse' => 1 + ])->save(); + } + + if($this->checkFieldExist('directus_files', 'filename')){ + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + [ + 'required' => 1 + ], + ['collection' => 'directus_files', 'field' => 'filename'] + )); + } + + if($this->checkFieldExist('directus_files', 'width')){ + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + [ + 'sort' => 10 + ], + ['collection' => 'directus_files', 'field' => 'width'] + )); + } + + if($this->checkFieldExist('directus_files', 'height')){ + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + [ + 'sort' => 11 + ], + ['collection' => 'directus_files', 'field' => 'height'] + )); + } + + if($this->checkFieldExist('directus_files', 'duration')){ + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + [ + 'readonly' => 1, + 'note' => 'Duration must be in seconds', + 'sort' => 12 + ], + ['collection' => 'directus_files', 'field' => 'duration'] + )); + } + + if($this->checkFieldExist('directus_files', 'filesize')){ + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + [ + 'sort' => 13 + ], + ['collection' => 'directus_files', 'field' => 'filesize'] + )); + } + + if($this->checkFieldExist('directus_files', 'uploaded_on')){ + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + [ + 'sort' => 8 + ], + ['collection' => 'directus_files', 'field' => 'uploaded_on'] + )); + + } + + if($this->checkFieldExist('directus_files', 'code')){ + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + [ + 'interface' => 'json' + ], + ['collection' => 'directus_files', 'interface' => 'code'] + )); + } + + if($this->checkFieldExist('directus_files', 'uploaded_by')){ + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + [ + 'type' => \Directus\Database\Schema\DataTypes::TYPE_USER_CREATED, + 'interface' => 'user-created', + 'sort' => 9 + ], + ['collection' => 'directus_files', 'field' => 'uploaded_by'] + )); + } + + if($this->checkFieldExist('directus_files', 'tags')){ + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + [ + 'options' => json_encode([ + 'placeholder' => 'Enter a keyword then hit enter...' + ]), + ], + ['collection' => 'directus_files', 'field' => 'tags'] + )); + } + + if($this->checkFieldExist('directus_files', 'description')){ + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + [ + 'options' => json_encode([ + 'toolbar' => ['bold','italic','underline','link','code'] + ]), + ], + ['collection' => 'directus_files', 'field' => 'description'] + )); + } + + if($this->checkFieldExist('directus_files', 'metadata')){ + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + [ + 'width' => 'full' + ], + ['collection' => 'directus_files', 'field' => 'metadata'] + )); + } + + if (!$filesTable->hasColumn('private_hash')) { + $filesTable->addColumn('private_hash', 'string', [ + 'limit' => 16, + 'null' => true, + 'default' => null + ])->save(); + } + + if(!$this->checkFieldExist('directus_files', 'private_hash')){ + $fieldsTable->insert([ + 'collection' => 'directus_files', + 'field' => 'private_hash', + 'type' => 'string', + 'interface'=>'text-input', + 'readonly' => 1, + 'hidden_browse' => 1, + 'hidden_detail' => 1 + ])->save(); + } + } + + public function checkFieldExist($collection,$field){ + $checkSql = sprintf('SELECT 1 FROM `directus_fields` WHERE `collection` = "%s" AND `field` = "%s";', $collection, $field); + return $this->query($checkSql)->fetch(); + } +} diff --git a/migrations/upgrades/20191129123300_use_new_wysiwyg.php b/migrations/upgrades/20191129123300_use_new_wysiwyg.php new file mode 100644 index 0000000000..f5ce6d740a --- /dev/null +++ b/migrations/upgrades/20191129123300_use_new_wysiwyg.php @@ -0,0 +1,24 @@ +execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + ['interface' => 'wysiwyg'], + ['interface' => 'wysiwyg_advanced'] + )); + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + ['interface' => 'wysiwyg'], + ['interface' => 'wysiwyg_full'] + )); + } +} diff --git a/migrations/upgrades/20191202164200_add_user_sessions.php b/migrations/upgrades/20191202164200_add_user_sessions.php new file mode 100644 index 0000000000..f7d41314e0 --- /dev/null +++ b/migrations/upgrades/20191202164200_add_user_sessions.php @@ -0,0 +1,58 @@ +hasTable('directus_user_sessions')) { + // Don't do anything if the table already exists + return; + } + + $table = $this->table('directus_user_sessions', ['signed' => false]); + + $table->addColumn('user', 'integer', [ + 'signed' => false, + 'null' => true, + 'default' => null + ]); + + $table->addColumn('token_type', 'string', [ + 'null' => true, + 'default' => null + ]); + + $table->addColumn('token', 'string', [ + 'limit' => 520, + 'encoding' => 'utf8', + 'null' => true, + 'default' => null + ]); + + $table->addColumn('ip_address', 'string', [ + 'limit' => 255, + 'encoding' => 'utf8', + 'null' => true, + 'default' => null + ]); + + $table->addColumn('user_agent', 'text', [ + 'default' => null, + 'null' => true, + 'default' => null + ]); + + $table->addColumn('created_on', 'datetime', [ + 'null' => true, + 'default' => null + ]); + + $table->addColumn('token_expired_at', 'datetime', [ + 'null' => true, + 'default' => null + ]); + + $table->create(); + } +} diff --git a/migrations/upgrades/20191202164201_add_webhooks.php b/migrations/upgrades/20191202164201_add_webhooks.php new file mode 100644 index 0000000000..858c1e89c2 --- /dev/null +++ b/migrations/upgrades/20191202164201_add_webhooks.php @@ -0,0 +1,50 @@ +hasTable('directus_webhooks')) { + // Don't do anything if the table already exists + return; + } + + $table = $this->table('directus_webhooks', ['signed' => false]); + + $table->addColumn('status', 'string', [ + 'limit' => 16, + 'default' => \Directus\Api\Routes\Webhook::STATUS_INACTIVE + ]); + + + $table->addColumn('http_action', 'string', [ + 'limit' => 255, + 'encoding' => 'utf8', + 'null' => true, + 'default' => null + ]); + + $table->addColumn('url', 'string', [ + 'limit' => 510, + 'encoding' => 'utf8', + 'null' => true, + 'default' => null + ]); + + $table->addColumn('collection', 'string', [ + 'limit' => 255, + 'null' => true, + 'default' => null + ]); + + $table->addColumn('directus_action', 'string', [ + 'limit' => 255, + 'encoding' => 'utf8', + 'null' => true, + 'default' => null + ]); + + $table->create(); + } +} diff --git a/migrations/upgrades/20191202164202_remove_activity_seen.php b/migrations/upgrades/20191202164202_remove_activity_seen.php new file mode 100644 index 0000000000..719451a2f8 --- /dev/null +++ b/migrations/upgrades/20191202164202_remove_activity_seen.php @@ -0,0 +1,15 @@ +hasTable('directus_activity_seen')) { + $this->table('directus_activity_seen')->drop(); + } + } +} diff --git a/migrations/upgrades/20191202164203_convert_user_roles.php b/migrations/upgrades/20191202164203_convert_user_roles.php new file mode 100644 index 0000000000..1d47ff753f --- /dev/null +++ b/migrations/upgrades/20191202164203_convert_user_roles.php @@ -0,0 +1,40 @@ +table('directus_users'); + + // ------------------------------------------------------------------------- + // Add role column to directus_users + // ------------------------------------------------------------------------- + if ($usersTable->hasColumn('role') == false) { + $usersTable->addColumn('role', 'integer', [ + 'null' => true, + 'default' => null + ]); + $usersTable->save(); + } + + // ------------------------------------------------------------------------- + // Add users' roles to directus_roles + // It does this by retrieving the role ID from directus_user_roles and adding + // that role to the role column in directus_users + // ------------------------------------------------------------------------- + if ($this->hasTable('directus_user_roles')) { + $stmt = $this->query("SELECT * FROM `directus_user_roles`"); + while($row = $stmt->fetch(PDO::FETCH_ASSOC)){ + $this->execute('UPDATE `directus_users` SET `role` = '.$row['role'].' where id = '.$row['user'].';'); + } + } + + // ------------------------------------------------------------------------- + // Remove directus_user_roles table + // ------------------------------------------------------------------------- + if ($this->hasTable('directus_user_roles')) { + $this->table('directus_user_roles')->drop(); + } + } +} diff --git a/migrations/upgrades/20191202164204_update_directus_users.php b/migrations/upgrades/20191202164204_update_directus_users.php new file mode 100644 index 0000000000..23ff79f702 --- /dev/null +++ b/migrations/upgrades/20191202164204_update_directus_users.php @@ -0,0 +1,39 @@ +table('directus_users'); + + // ------------------------------------------------------------------------- + // Add theme column + // ------------------------------------------------------------------------- + if ($usersTable->hasColumn('theme') == false) { + $usersTable->addColumn('theme', 'string', [ + 'limit' => 100, + 'encoding' => 'utf8', + 'null' => true, + 'default' => 'auto' + ]); + } + + // ------------------------------------------------------------------------- + // Add theme column + // ------------------------------------------------------------------------- + if ($usersTable->hasColumn('2fa_secret') == false) { + $usersTable->addColumn('2fa_secret', 'string', [ + 'limit' => 100, + 'encoding' => 'utf8', + 'null' => true, + 'default' => null + ]); + } + + // ------------------------------------------------------------------------- + // Save changes to table + // ------------------------------------------------------------------------- + $usersTable->save(); + } +} diff --git a/migrations/upgrades/20191202164205_update_directus_settings.php b/migrations/upgrades/20191202164205_update_directus_settings.php new file mode 100644 index 0000000000..74fcd232e9 --- /dev/null +++ b/migrations/upgrades/20191202164205_update_directus_settings.php @@ -0,0 +1,123 @@ +table('directus_settings'); + + // ------------------------------------------------------------------------- + // Remove deprecated setting fields + // ------------------------------------------------------------------------- + $this->removeSetting('color'); + $this->removeSetting('thumbnail_dimensions'); + $this->removeSetting('thumbnail_quality_tags'); + $this->removeSetting('thumbnail_actions'); + $this->removeSetting('thumbnail_cache_ttl'); + $this->removeSetting('thumbnail_not_found_location'); + + // ------------------------------------------------------------------------- + // Rename logo to project_logo + // ------------------------------------------------------------------------- + if ($this->hasSetting('logo')) { + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_settings', + ['key' => 'project_logo'], + ['key' => 'logo'] + )); + } + + // ------------------------------------------------------------------------- + // Add new setting fields + // ------------------------------------------------------------------------- + $newSettings = [ + [ + 'key' => 'project_url', + 'value' => '', + ], + [ + 'key' => 'project_color', + 'value' => '#13181a', + ], + [ + 'key' => 'project_foreground', + 'value' => '', + ], + [ + 'key' => 'project_background', + 'value' => '', + ], + [ + 'key' => 'default_locale', + 'value' => 'en-US', + ], + [ + 'key' => 'telemetry', + 'value' => '1' + ], + [ + 'key' => 'password_policy', + 'value' => '' + ], + [ + 'key' => 'login_attempts_allowed', + 'value' => '' + ], + [ + 'key' => 'file_max_size', + 'value' => '100MB' + ], + [ + 'key' => 'file_mimetype_whitelist', + 'value' => '' + ], + [ + 'key' => 'asset_whitelist_system', + 'value' => json_encode([ + [ + "key" => "card", + "width" => 200, + "height" => 200, + "fit" => "crop", + "quality" => 80 + ], + [ + "key" => "avatar", + "width" => 100, + "height" => 100, + "fit" => "crop", + "quality" => 80 + ] + ]) + ], + [ + 'key' => 'asset_whitelist', + 'value' => '' + ] + ]; + + foreach($newSettings as $setting) { + if ($this->hasSetting($setting['key']) == false) { + $settingsTable->insert($setting); + } + } + + // ------------------------------------------------------------------------- + // Save the changes + // ------------------------------------------------------------------------- + $settingsTable->save(); + } + + public function hasSetting($field){ + $checkSql = sprintf('SELECT 1 FROM `directus_settings` WHERE `key` = "%s"', $field); + return $this->query($checkSql)->fetch(); + } + + public function removeSetting($field) { + if (!$this->hasSetting($field)) { + $this->execute('DELETE FROM `directus_settings` where `key` = "' . $field . '";'); + } + } +} diff --git a/migrations/upgrades/20191202164206_update_directus_files.php b/migrations/upgrades/20191202164206_update_directus_files.php new file mode 100644 index 0000000000..76af64b088 --- /dev/null +++ b/migrations/upgrades/20191202164206_update_directus_files.php @@ -0,0 +1,59 @@ +table('directus_files'); + + // ------------------------------------------------------------------------- + // Rename filename to filename_disk + // ------------------------------------------------------------------------- + if ($filesTable->hasColumn('filename')) { + $filesTable->renameColumn('filename', 'filename_disk'); + } + + // ------------------------------------------------------------------------- + // Add filename_download column + // ------------------------------------------------------------------------- + if ($filesTable->hasColumn('filename_download') == false) { + $filesTable->addColumn('filename_download', 'string', [ + 'limit' => 255, + 'null' => false + ]); + } + + // ------------------------------------------------------------------------- + // Add private hash column + // ------------------------------------------------------------------------- + if ($filesTable->hasColumn('private_hash') == false) { + $filesTable->addColumn('private_hash', 'string', [ + 'limit' => 16, + 'null' => true, + 'default' => null + ]); + } + + // ------------------------------------------------------------------------- + // Add a private hash for all existing files + // ------------------------------------------------------------------------- + $filesTable->save(); // Make sure the private hash column above is saved + + $filesWithoutPrivateHash = $this->fetchAll('SELECT id FROM directus_files WHERE private_hash = null;'); + + foreach($filesWithoutPrivateHash as $key => $value) { + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_files', + ['private_hash' => get_random_string()], + ['id' => $value['id']] + )); + } + + // ------------------------------------------------------------------------- + // Save changes to table + // ------------------------------------------------------------------------- + $filesTable->save(); + } +} diff --git a/migrations/upgrades/20191202164207_update_directus_roles.php b/migrations/upgrades/20191202164207_update_directus_roles.php new file mode 100644 index 0000000000..3c34136cb7 --- /dev/null +++ b/migrations/upgrades/20191202164207_update_directus_roles.php @@ -0,0 +1,59 @@ +table('directus_roles'); + + // ------------------------------------------------------------------------- + // Remove unused nav_blacklist column + // ------------------------------------------------------------------------- + if ($rolesTable->hasColumn('nav_blacklist')) { + $rolesTable->removeColumn('nav_blacklist'); + } + + // ------------------------------------------------------------------------- + // Remove deprecated nav_override + // ------------------------------------------------------------------------- + if ($rolesTable->hasColumn('nav_override')) { + $rolesTable->removeColumn('nav_override'); + } + + // ------------------------------------------------------------------------- + // Add module_listing column + // ------------------------------------------------------------------------- + if ($rolesTable->hasColumn('module_listing') == false) { + $rolesTable->addColumn('module_listing', 'string', [ + 'null' => true, + 'default' => null + ]); + } + + // ------------------------------------------------------------------------- + // Add collection_listing column + // ------------------------------------------------------------------------- + if ($rolesTable->hasColumn('collection_listing') == false) { + $rolesTable->addColumn('collection_listing', 'string', [ + 'null' => true, + 'default' => null + ]); + } + + // ------------------------------------------------------------------------- + // Add enforce_2fa column + // ------------------------------------------------------------------------- + if ($rolesTable->hasColumn('enforce_2fa') == false) { + $rolesTable->addColumn('enforce_2fa', 'integer', [ + 'null' => true, + 'default' => false + ]); + } + + // ------------------------------------------------------------------------- + // Save changes to table + // ------------------------------------------------------------------------- + $rolesTable->save(); + } +} diff --git a/migrations/upgrades/20191202164208_reset_directus_relations.php b/migrations/upgrades/20191202164208_reset_directus_relations.php new file mode 100644 index 0000000000..042ae9636e --- /dev/null +++ b/migrations/upgrades/20191202164208_reset_directus_relations.php @@ -0,0 +1,98 @@ +table('directus_relations'); + + // ------------------------------------------------------------------------- + // Delete all system relations from directus_relations + // This will not delete rows that were added by the user + // ------------------------------------------------------------------------- + $this->execute('DELETE FROM directus_relations WHERE collection_many LIKE "directus\_%" AND collection_one LIKE "directus\_%"'); + + // ------------------------------------------------------------------------- + // Add v8.0.0 data + // ------------------------------------------------------------------------- + $data = [ + [ + 'collection_many' => 'directus_activity', + 'field_many' => 'action_by', + 'collection_one' => 'directus_users' + ], + [ + 'collection_many' => 'directus_collections_presets', + 'field_many' => 'user', + 'collection_one' => 'directus_users' + ], + [ + 'collection_many' => 'directus_collections_presets', + 'field_many' => 'group', + 'collection_one' => 'directus_groups' + ], + [ + 'collection_many' => 'directus_fields', + 'field_many' => 'collection', + 'collection_one' => 'directus_collections', + 'field_one' => 'fields' + ], + [ + 'collection_many' => 'directus_files', + 'field_many' => 'uploaded_by', + 'collection_one' => 'directus_users' + ], + [ + 'collection_many' => 'directus_files', + 'field_many' => 'folder', + 'collection_one' => 'directus_folders' + ], + [ + 'collection_many' => 'directus_folders', + 'field_many' => 'parent_folder', + 'collection_one' => 'directus_folders' + ], + [ + 'collection_many' => 'directus_permissions', + 'field_many' => 'group', + 'collection_one' => 'directus_groups' + ], + [ + 'collection_many' => 'directus_revisions', + 'field_many' => 'activity', + 'collection_one' => 'directus_activity' + ], + [ + 'collection_many' => 'directus_users', + 'field_many' => 'role', + 'collection_one' => 'directus_roles', + 'field_one' => 'users' + ], + [ + 'collection_many' => 'directus_users', + 'field_many' => 'avatar', + 'collection_one' => 'directus_files' + ] + ]; + + // ------------------------------------------------------------------------- + // Add the data to the table + // ------------------------------------------------------------------------- + $relationsTable->insert($data); + + // ------------------------------------------------------------------------- + // Save changes to table + // ------------------------------------------------------------------------- + $relationsTable->save(); + } +} diff --git a/migrations/upgrades/20191202164209_reset_directus_fields.php b/migrations/upgrades/20191202164209_reset_directus_fields.php new file mode 100644 index 0000000000..b515b17a42 --- /dev/null +++ b/migrations/upgrades/20191202164209_reset_directus_fields.php @@ -0,0 +1,2068 @@ +table('directus_fields'); + + // ------------------------------------------------------------------------- + // Delete all rows that apply to directus_* collections from fields + // ------------------------------------------------------------------------- + $this->execute('DELETE FROM directus_fields WHERE collection LIKE "directus\_%"'); + + // ------------------------------------------------------------------------- + // Add v8.0.0 data + // ------------------------------------------------------------------------- + $data = [ + // --------------------------------------------------------------------- + // directus_fields + [ + 'collection' => 'directus_fields', + 'field' => 'id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'primary-key', + 'locked' => 1, + 'required' => 1, + 'hidden_detail' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'collection', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, + 'interface' => 'many-to-one', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'field', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'type', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'primary-key', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'interface', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'primary-key', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'options', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'json', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'locked', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'translation', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'repeater', + 'locked' => 1, + 'options' => '{ + "fields": [ + { + "field": "locale", + "type": "string", + "interface": "language", + "options": { + "limit": true + }, + "width": "half" + }, + { + "field": "translation", + "type": "string", + "interface": "text-input", + "width": "half" + } + ] + }' + ], + [ + 'collection' => 'directus_fields', + 'field' => 'readonly', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'validation', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + ], + [ + 'collection' => 'directus_fields', + 'field' => 'required', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'sort', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_SORT, + 'interface' => 'sort', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'note', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'hidden_detail', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'hidden_browse', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'width', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'numeric', + 'locked' => 1 + ], + [ + 'collection' => 'directus_fields', + 'field' => 'group', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, + 'interface' => 'many-to-one', + 'locked' => 1 + ], + + // --------------------------------------------------------------------- + // directus_activity + [ + 'collection' => 'directus_activity', + 'field' => 'id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'primary-key', + 'locked' => 1, + 'readonly' => 1, + 'required' => 1, + 'hidden_detail' => 1 + ], + [ + 'collection' => 'directus_activity', + 'field' => 'action', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'change_history' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 1, + 'width' => 'full' + ], + [ + 'collection' => 'directus_activity', + 'field' => 'collection', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'collections', + 'options' => json_encode([ + 'iconRight' => 'list_alt', + 'include_system' => true + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 2, + 'width' => 'half' + ], + [ + 'collection' => 'directus_activity', + 'field' => 'item', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'link' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 3, + 'width' => 'half' + ], + [ + 'collection' => 'directus_activity', + 'field' => 'action_by', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'user', + 'options' => json_encode([ + 'iconRight' => 'account_circle' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 4, + 'width' => 'half' + ], + [ + 'collection' => 'directus_activity', + 'field' => 'action_on', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_DATETIME, + 'interface' => 'datetime', + 'options' => json_encode([ + 'showRelative' => true, + 'iconRight' => 'calendar_today' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 5, + 'width' => 'half' + ], + [ + 'collection' => 'directus_activity', + 'field' => 'edited_on', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_DATETIME, + 'interface' => 'datetime', + 'options' => json_encode([ + 'showRelative' => true, + 'iconRight' => 'edit' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 6, + 'width' => 'half' + ], + [ + 'collection' => 'directus_activity', + 'field' => 'comment_deleted_on', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_DATETIME, + 'interface' => 'datetime', + 'options' => json_encode([ + 'showRelative' => true, + 'iconRight' => 'delete_outline' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 7, + 'width' => 'half' + ], + [ + 'collection' => 'directus_activity', + 'field' => 'ip', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'my_location' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 8, + 'width' => 'half' + ], + [ + 'collection' => 'directus_activity', + 'field' => 'user_agent', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'devices_other' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 9, + 'width' => 'half' + ], + [ + 'collection' => 'directus_activity', + 'field' => 'comment', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'textarea', + 'locked' => 1, + 'readonly' => 1, + 'sort' => 10, + 'width' => 'full' + ], + + // --------------------------------------------------------------------- + // directus_collections_presets + [ + 'collection' => 'directus_collection_presets', + 'field' => 'id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'primary-key', + 'locked' => 1 + ], + [ + 'collection' => 'directus_collection_presets', + 'field' => 'title', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_collection_presets', + 'field' => 'user', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'user', + 'locked' => 1 + ], + [ + 'collection' => 'directus_collection_presets', + 'field' => 'role', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, + 'interface' => 'many-to-one', + 'locked' => 1 + ], + [ + 'collection' => 'directus_collection_presets', + 'field' => 'collection', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, + 'interface' => 'many-to-one', + 'locked' => 1 + ], + [ + 'collection' => 'directus_collection_presets', + 'field' => 'search_query', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_collection_presets', + 'field' => 'filters', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'json', + 'locked' => 1 + ], + [ + 'collection' => 'directus_collection_presets', + 'field' => 'view_options', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'json', + 'locked' => 1 + ], + [ + 'collection' => 'directus_collection_presets', + 'field' => 'view_type', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_collection_presets', + 'field' => 'view_query', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'json', + 'locked' => 1 + ], + + // --------------------------------------------------------------------- + // directus_collections + [ + 'collection' => 'directus_collections', + 'field' => 'fields', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_O2M, + 'interface' => 'one-to-many', + 'locked' => 1, + 'hidden_detail' => 1, + 'hidden_browse' => 1, + 'sort' => 1 + ], + [ + 'collection' => 'directus_collections', + 'field' => 'collection', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'primary-key', + 'locked' => 1, + 'readonly' => 1, + 'required' => 1, + 'sort' => 2, + 'width' => 'half' + ], + [ + 'collection' => 'directus_collections', + 'field' => 'note', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'sort' => 3, + 'width' => 'half', + 'note' => 'An internal description.' + ], + [ + 'collection' => 'directus_collections', + 'field' => 'managed', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1, + 'sort' => 4, + 'width' => 'half', + 'hidden_detail' => 1, + 'note' => '[Learn More](https://docs.directus.io/guides/collections.html#managing-collections).' + ], + [ + 'collection' => 'directus_collections', + 'field' => 'hidden', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1, + 'sort' => 5, + 'width' => 'half', + 'note' => '[Learn More](https://docs.directus.io/guides/collections.html#hidden).' + ], + [ + 'collection' => 'directus_collections', + 'field' => 'single', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1, + 'sort' => 6, + 'width' => 'half', + 'note' => '[Learn More](https://docs.directus.io/guides/collections.html#single).' + ], + [ + 'collection' => 'directus_collections', + 'field' => 'translation', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'repeater', + 'locked' => 1, + 'sort' => 7, + 'hidden_detail' => 0, + 'options' => '{ + "fields": [ + { + "field": "locale", + "type": "string", + "interface": "language", + "options": { + "limit": true + }, + "width": "half" + }, + { + "field": "translation", + "type": "string", + "interface": "text-input", + "width": "half" + } + ] + }' + ], + [ + 'collection' => 'directus_collections', + 'field' => 'icon', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'icon', + 'locked' => 1, + 'sort' => 8, + 'note' => 'The icon shown in the App\'s navigation sidebar.' + ], + + // --------------------------------------------------------------------- + // directus_files + [ + 'collection' => 'directus_files', + 'field' => 'preview', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ALIAS, + 'interface' => 'file-preview', + 'locked' => 1, + 'sort' => 1, + 'width' => 'full' + ], + [ + 'collection' => 'directus_files', + 'field' => 'title', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'placeholder' => 'Enter a descriptive title...', + 'iconRight' => 'title' + ]), + 'locked' => 1, + 'sort' => 2, + 'width' => 'full' + ], + [ + 'collection' => 'directus_files', + 'field' => 'tags', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ARRAY, + 'interface' => 'tags', + 'options' => json_encode([ + 'placeholder' => 'Enter a keyword then hit enter...' + ]), + 'sort' => 3, + 'width' => 'half', + 'locked' => 1 + ], + [ + 'collection' => 'directus_files', + 'field' => 'location', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'placeholder' => 'Enter a location...', + 'iconRight' => 'place' + ]), + 'sort' => 4, + 'width' => 'half', + 'locked' => 1 + ], + [ + 'collection' => 'directus_files', + 'field' => 'description', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'wysiwyg', + 'options' => json_encode([ + 'toolbar' => ['bold','italic','underline','link','code'] + ]), + 'sort' => 5, + 'width' => 'full', + 'locked' => 1 + ], + [ + 'collection' => 'directus_files', + 'field' => 'filename_download', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'options' => json_encode([ + 'monospace' => true, + 'iconRight' => 'get_app' + ]), + 'sort' => 6, + 'width' => 'full' + ], + [ + 'collection' => 'directus_files', + 'field' => 'filename_disk', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'placeholder' => 'Enter a unique file name...', + 'iconRight' => 'insert_drive_file' + ]), + 'locked' => 1, + 'sort' => 7, + 'width' => 'full' + ], + [ + 'collection' => 'directus_files', + 'field' => 'private_hash', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface'=> 'slug', + 'width' => 'half', + 'locked' => 1, + 'sort' => 8, + 'options' => json_encode([ + 'iconRight' => 'lock' + ]) + ], + [ + 'collection' => 'directus_files', + 'field' => 'checksum', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'readonly' => 1, + 'sort' => 9, + 'width' => 'half', + 'options' => json_encode([ + 'iconRight' => 'check', + 'monospace' => true + ]) + ], + [ + 'collection' => 'directus_files', + 'field' => 'uploaded_on', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_DATETIME, + 'interface' => 'datetime', + 'options' => json_encode([ + 'iconRight' => 'today' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 10, + 'width' => 'half', + 'required' => 1 + ], + [ + 'collection' => 'directus_files', + 'field' => 'uploaded_by', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_USER_CREATED, + 'interface' => 'user-created', + 'locked' => 1, + 'readonly' => 1, + 'sort' => 11, + 'width' => 'half', + 'required' => 1 + ], + [ + 'collection' => 'directus_files', + 'field' => 'width', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'numeric', + 'options' => json_encode([ + 'iconRight' => 'straighten' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 12, + 'width' => 'half' + ], + [ + 'collection' => 'directus_files', + 'field' => 'height', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'numeric', + 'options' => json_encode([ + 'iconRight' => 'straighten' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 13, + 'width' => 'half' + ], + [ + 'collection' => 'directus_files', + 'field' => 'duration', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'numeric', + 'options' => json_encode([ + 'iconRight' => 'timer' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 14, + 'width' => 'half' + ], + [ + 'collection' => 'directus_files', + 'field' => 'filesize', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'file-size', + 'options' => json_encode([ + 'iconRight' => 'storage' + ]), + 'locked' => 1, + 'readonly' => 1, + 'sort' => 15, + 'width' => 'half' + ], + [ + 'collection' => 'directus_files', + 'field' => 'metadata', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'key-value', + 'locked' => 1, + 'sort' => 15, + 'width' => 'full', + 'options' => json_encode([ + 'keyInterface' => 'text-input', + 'keyDataType' => 'string', + 'keyOptions' => [ + 'monospace' => true, + 'placeholder' => 'Key' + ], + 'valueInterface' => 'text-input', + 'valueDataType' => 'string', + 'valueOptions' => [ + 'monospace' => true, + 'placeholder' => 'Value' + ] + ]) + ], + [ + 'collection' => 'directus_files', + 'field' => 'data', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ALIAS, + 'interface' => 'file', + 'locked' => 1, + 'hidden_detail' => 1 + ], + [ + 'collection' => 'directus_files', + 'field' => 'id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'primary-key', + 'locked' => 1, + 'required' => 1, + 'hidden_detail' => 1 + ], + [ + 'collection' => 'directus_files', + 'field' => 'type', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'readonly' => 1, + 'hidden_detail' => 1 + ], + [ + 'collection' => 'directus_files', + 'field' => 'charset', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'readonly' => 1, + 'hidden_detail' => 1, + 'hidden_browse' => 1 + ], + [ + 'collection' => 'directus_files', + 'field' => 'embed', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'readonly' => 1, + 'hidden_detail' => 1 + ], + [ + 'collection' => 'directus_files', + 'field' => 'folder', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, + 'interface' => 'many-to-one', + 'locked' => 1, + 'hidden_detail' => 1 + ], + [ + 'collection' => 'directus_files', + 'field' => 'storage', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'hidden_detail' => 1, + 'hidden_browse' => 1 + ], + + // --------------------------------------------------------------------- + // directus_folders + [ + 'collection' => 'directus_folders', + 'field' => 'id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'primary-key', + 'locked' => 1, + 'required' => 1, + 'hidden_detail' => 1 + ], + [ + 'collection' => 'directus_folders', + 'field' => 'name', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_folders', + 'field' => 'parent_folder', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, + 'interface' => 'many-to-one', + 'locked' => 1 + ], + + // --------------------------------------------------------------------- + // directus_roles + [ + 'collection' => 'directus_roles', + 'field' => 'id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'primary-key', + 'locked' => 1, + 'required' => 1, + 'hidden_detail' => 1 + ], + [ + 'collection' => 'directus_roles', + 'field' => 'external_id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'readonly' => 1, + 'hidden_detail' => 1, + 'hidden_browse' => 1 + ], + [ + 'collection' => 'directus_roles', + 'field' => 'name', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'sort' => 1, + 'width' => 'half', + 'required' => 1 + ], + [ + 'collection' => 'directus_roles', + 'field' => 'description', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'sort' => 2, + 'width' => 'half' + ], + [ + 'collection' => 'directus_roles', + 'field' => 'ip_whitelist', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ARRAY, + 'interface' => 'tags', + 'options' => json_encode([ + '' => 'Add an IP address...' + ]), + 'locked' => 1 + ], + [ + 'collection' => 'directus_roles', + 'field' => 'enforce_2fa', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1 + ], + [ + 'collection' => 'directus_roles', + 'field' => 'users', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_O2M, + 'interface' => 'one-to-many', + 'locked' => 1, + 'options' => json_encode([ + 'fields' => "first_name,last_name" + ]) + ], + [ + 'collection' => 'directus_roles', + 'field' => 'module_listing', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'repeater', + 'locked' => 1, + 'options' => '{ + "fields": [ + { + "field": "name", + "interface": "text-input", + "type": "string", + "width": "half" + }, + { + "field": "link", + "interface": "text-input", + "type": "string", + "width": "half" + }, + { + "field": "icon", + "interface": "icon", + "type": "string", + "width": "full" + } + ] + }' + ], + [ + 'collection' => 'directus_roles', + 'field' => 'collection_listing', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'repeater', + 'locked' => 1, + 'options' => '{ + "fields": [ + { + "field": "groups", + "width": "full", + "interface": "repeater", + "type": "JSON", + "options": { + "template": "{{ label }}", + "fields": [ + { + "field": "label", + "interface": "text-input", + "type": "string" + }, + { + "field": "value", + "interface": "text-input", + "type": "string" + }, + { + "field": "icon", + "width": "full", + "interface": "icon", + "type": "string" + } + ] + } + } + ] + }' + ], + + // --------------------------------------------------------------------- + // directus_permissions + [ + 'collection' => 'directus_permissions', + 'field' => 'id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'primary-key', + 'locked' => 1, + 'required' => 1, + 'hidden_detail' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'collection', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, + 'interface' => 'many-to-one', + 'locked' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'role', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, + 'interface' => 'many-to-one', + 'locked' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'status', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'create', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'read', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'update', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'delete', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'primary-key', + 'locked' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'comment', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'explain', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'status_blacklist', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ARRAY, + 'interface' => 'tags', + 'locked' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'read_field_blacklist', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ARRAY, + 'interface' => 'tags', + 'locked' => 1 + ], + [ + 'collection' => 'directus_permissions', + 'field' => 'write_field_blacklist', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ARRAY, + 'interface' => 'tags', + 'locked' => 1 + ], + + // --------------------------------------------------------------------- + // directus_relations + [ + 'collection' => 'directus_relations', + 'field' => 'id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'primary-key', + 'locked' => 1 + ], + [ + 'collection' => 'directus_relations', + 'field' => 'collection_many', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'collections', + 'locked' => 1 + ], + [ + 'collection' => 'directus_relations', + 'field' => 'field_many', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_relations', + 'field' => 'collection_one', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'collections', + 'locked' => 1 + ], + [ + 'collection' => 'directus_relations', + 'field' => 'field_one', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_relations', + 'field' => 'junction_field', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + + // --------------------------------------------------------------------- + // directus_revisions + [ + 'collection' => 'directus_revisions', + 'field' => 'id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'primary-key', + 'locked' => 1 + ], + [ + 'collection' => 'directus_revisions', + 'field' => 'activity', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, + 'interface' => 'many-to-one', + 'locked' => 1 + ], + [ + 'collection' => 'directus_revisions', + 'field' => 'collection', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, + 'interface' => 'many-to-one', + 'locked' => 1 + ], + [ + 'collection' => 'directus_revisions', + 'field' => 'item', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_revisions', + 'field' => 'data', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'json', + 'locked' => 1 + ], + [ + 'collection' => 'directus_revisions', + 'field' => 'delta', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'json', + 'locked' => 1 + ], + [ + 'collection' => 'directus_revisions', + 'field' => 'parent_item', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1 + ], + [ + 'collection' => 'directus_revisions', + 'field' => 'parent_collection', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'collections', + 'locked' => 1 + ], + [ + 'collection' => 'directus_revisions', + 'field' => 'parent_changed', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1 + ], + + // --------------------------------------------------------------------- + // directus_revisions + [ + 'collection' => 'directus_settings', + 'field' => 'project_name', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'title' + ]), + 'locked' => 1, + 'required' => 1, + 'width' => 'half', + 'note' => 'Logo in the top-left of the App (40x40)', + 'sort' => 1 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'project_url', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'link' + ]), + 'locked' => 1, + 'width' => 'half', + 'note' => 'External link for the App\'s top-left logo', + 'sort' => 2 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'project_logo', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_FILE, + 'interface' => 'file', + 'locked' => 1, + 'width' => 'half', + 'note' => 'A 40x40 brand logo, ideally a white SVG/PNG', + 'sort' => 3 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'project_color', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'color', + 'locked' => 1, + 'width' => 'half', + 'note' => 'Color for login background and App\'s logo', + 'sort' => 4 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'project_foreground', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_FILE, + 'interface' => 'file', + 'locked' => 1, + 'width' => 'half', + 'note' => 'Centered image (eg: logo) for the login page', + 'sort' => 5 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'project_background', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_FILE, + 'interface' => 'file', + 'locked' => 1, + 'width' => 'half', + 'note' => 'Full-screen background for the login page', + 'sort' => 6 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'default_locale', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'language', + 'locked' => 1, + 'width' => 'half', + 'note' => 'Default locale for Directus Users', + 'sort' => 7, + 'options' => json_encode([ + 'limit' => true + ]) + ], + [ + 'collection' => 'directus_settings', + 'field' => 'telemetry', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1, + 'width' => 'half', + 'note' => 'Learn More', + 'sort' => 8 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'data_divider', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ALIAS, + 'interface' => 'divider', + 'options' => json_encode([ + 'style' => 'large', + 'title' => 'Data', + 'hr' => true + ]), + 'locked' => 1, + 'width' => 'full', + 'hidden_browse' => 1, + 'sort' => 10 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'default_limit', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'numeric', + 'options' => json_encode([ + 'iconRight' => 'keyboard_tab' + ]), + 'locked' => 1, + 'required' => 1, + 'width' => 'half', + 'note' => 'Default item count in API and App responses', + 'sort' => 11 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'sort_null_last', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1, + 'note' => 'NULL values are sorted last', + 'width' => 'half', + 'sort' => 12 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'security_divider', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ALIAS, + 'interface' => 'divider', + 'options' => json_encode([ + 'style' => 'large', + 'title' => 'Security', + 'hr' => true + ]), + 'locked' => 1, + 'hidden_browse' => 1, + 'width' => 'full', + 'sort' => 20 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'auto_sign_out', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'numeric', + 'options' => json_encode([ + 'iconRight' => 'timer' + ]), + 'locked' => 1, + 'required' => 1, + 'width' => 'half', + 'note' => 'Minutes before idle users are signed out', + 'sort' => 22 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'login_attempts_allowed', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'numeric', + 'options' => json_encode([ + 'iconRight' => 'lock' + ]), + 'locked' => 1, + 'width' => 'half', + 'note' => 'Failed login attempts before suspending users', + 'sort' => 23 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'password_policy', + 'type' => 'string', + 'note' => 'Weak: Minimum length 8; Strong: 1 small-case letter, 1 capital letter, 1 digit, 1 special character and the length should be minimum 8', + 'interface' => 'dropdown', + 'options' => json_encode([ + 'choices' => [ + '' => 'None', + '/^.{8,}$/' => 'Weak', + '/(?=^.{8,}$)(?=.*\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()_+}{\';\'?>.<,])(?!.*\s).*$/' => 'Strong' + ] + ]), + 'sort' => 24, + 'locked' => 1, + 'width' => 'half' + ], + [ + 'collection' => 'directus_settings', + 'field' => 'files_divider', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ALIAS, + 'interface' => 'divider', + 'options' => json_encode([ + 'style' => 'large', + 'title' => 'Files & Thumbnails', + 'hr' => true + ]), + 'locked' => 1, + 'hidden_browse' => 1, + 'width' => 'full', + 'sort' => 30 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'file_naming', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'dropdown', + 'locked' => 1, + 'width' => 'half', + 'note' => 'File-system naming convention for uploads', + 'sort' => 31, + 'options' => json_encode([ + 'choices' => [ + 'uuid' => 'UUID (Obfuscated)', + 'file_name' => 'File Name (Readable)' + ] + ]) + ], + [ + 'collection' => 'directus_settings', + 'field' => 'file_max_size', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'placeholder' => 'eg: 4MB', + 'iconRight' => 'storage' + ]), + 'locked' => 1, + 'width' => 'half', + 'sort' => 32 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'file_mimetype_whitelist', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ARRAY, + 'interface' => 'tags', + 'options' => json_encode([ + 'placeholder' => 'Enter a file mimetype then hit enter (eg: image/jpeg)' + ]), + 'locked' => 1, + 'width' => 'full', + 'sort' => 33 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'asset_whitelist', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'repeater', + 'width' => 'full', + 'note' => 'Defines how the thumbnail will be generated based on the requested params.', + 'sort' => 34, + 'options' => json_encode([ + 'template' => '{{key}}', + 'fields' => [ + [ + 'field' => 'key', + 'interface' => 'slug', + 'width' => 'half', + 'type' => 'string', + 'required' => true + ], + [ + 'field' => 'fit', + 'interface' => 'dropdown', + 'width' => 'half', + 'type' => 'string', + 'options' => [ + 'choices' => [ + 'crop' => 'Crop (forces exact size)', + 'contain' => 'Contain (preserve aspect ratio)' + ] + ], + 'required' => true + ], + [ + 'field' => 'width', + 'interface' => 'numeric', + 'width' => 'half', + 'type' => 'integer', + 'required' => true + ], + [ + 'field' => 'height', + 'interface' => 'numeric', + 'width' => 'half', + 'type' => 'integer', + 'required' => true + ], + [ + 'field' => 'quality', + 'interface' => 'slider', + 'width' => 'full', + 'type' => 'integer', + 'default' => 80, + 'options' => [ + 'min' => 0, + 'max' => 100, + 'step' => 1 + ], + 'required' => true + ] + ] + ]) + ], + [ + 'collection' => 'directus_settings', + 'field' => 'asset_whitelist_system', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'json', + 'readonly' => 1, + 'width' => 'half', + 'hidden_browse' => 1, + 'hidden_detail' => 1, + 'sort' => 35 + ], + [ + 'collection' => 'directus_settings', + 'field' => 'youtube_api_key', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'videocam' + ]), + 'locked' => 1, + 'width' => 'full', + 'note' => 'Allows fetching more YouTube Embed info', + 'sort' => 36 + ], + + // --------------------------------------------------------------------- + // directus_users + [ + 'collection' => 'directus_users', + 'field' => 'id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'primary-key', + 'locked' => 1, + 'required' => 1, + 'hidden_detail' => 1, + 'sort' => 1 + ], + [ + 'collection' => 'directus_users', + 'field' => 'status', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STATUS, + 'interface' => 'status', + 'options' => json_encode([ + 'status_mapping' => [ + 'draft' => [ + 'name' => 'Draft', + 'text_color' => 'white', + 'background_color' => 'light-gray', + 'listing_subdued' => false, + 'listing_badge' => true, + 'soft_delete' => false, + ], + 'invited' => [ + 'name' => 'Invited', + 'text_color' => 'white', + 'background_color' => 'light-gray', + 'listing_subdued' => false, + 'listing_badge' => true, + 'soft_delete' => false, + ], + 'active' => [ + 'name' => 'Active', + 'text_color' => 'white', + 'background_color' => 'success', + 'listing_subdued' => false, + 'listing_badge' => false, + 'soft_delete' => false, + ], + 'suspended' => [ + 'name' => 'Suspended', + 'text_color' => 'white', + 'background_color' => 'light-gray', + 'listing_subdued' => false, + 'listing_badge' => true, + 'soft_delete' => false, + ], + 'deleted' => [ + 'name' => 'Deleted', + 'text_color' => 'white', + 'background_color' => 'danger', + 'listing_subdued' => false, + 'listing_badge' => true, + 'soft_delete' => true, + ] + ] + ]), + 'locked' => 1, + 'sort' => 2, + 'required' => 1 + ], + [ + 'collection' => 'directus_users', + 'field' => 'first_name', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'account_circle' + ]), + 'locked' => 1, + 'required' => 1, + 'sort' => 3, + 'width' => 'half' + ], + [ + 'collection' => 'directus_users', + 'field' => 'last_name', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'account_circle' + ]), + 'locked' => 1, + 'required' => 1, + 'sort' => 4, + 'width' => 'half' + ], + [ + 'collection' => 'directus_users', + 'field' => 'email', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'alternate_email' + ]), + 'locked' => 1, + 'validation' => '$email', + 'required' => 1, + 'sort' => 5, + 'width' => 'half' + ], + [ + 'collection' => 'directus_users', + 'field' => 'email_notifications', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_BOOLEAN, + 'interface' => 'toggle', + 'locked' => 1, + 'sort' => 6, + 'width' => 'half' + ], + [ + 'collection' => 'directus_users', + 'field' => 'password', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_HASH, + 'interface' => 'password', + 'locked' => 1, + 'required' => 1, + 'sort' => 7, + 'width' => 'half' + ], + [ + 'collection' => 'directus_users', + 'field' => 'role', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_M2O, + 'interface' => 'user-roles', + 'locked' => 1, + 'sort' => 8, + 'width' => 'half', + 'required' => 1 + ], + [ + 'collection' => 'directus_users', + 'field' => 'company', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'location_city' + ]), + 'sort' => 9, + 'width' => 'half' + ], + [ + 'collection' => 'directus_users', + 'field' => 'title', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'iconRight' => 'text_fields' + ]), + 'sort' => 10, + 'width' => 'half' + ], + [ + 'collection' => 'directus_users', + 'field' => 'timezone', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'dropdown', + 'options' => json_encode([ + 'choices' => [ + 'Pacific/Midway' => '(UTC-11:00) Midway Island', + 'Pacific/Samoa' => '(UTC-11:00) Samoa', + 'Pacific/Honolulu' => '(UTC-10:00) Hawaii', + 'US/Alaska' => '(UTC-09:00) Alaska', + 'America/Los_Angeles' => '(UTC-08:00) Pacific Time (US & Canada)', + 'America/Tijuana' => '(UTC-08:00) Tijuana', + 'US/Arizona' => '(UTC-07:00) Arizona', + 'America/Chihuahua' => '(UTC-07:00) Chihuahua', + 'America/Mexico/La_Paz' => '(UTC-07:00) La Paz', + 'America/Mazatlan' => '(UTC-07:00) Mazatlan', + 'US/Mountain' => '(UTC-07:00) Mountain Time (US & Canada)', + 'America/Managua' => '(UTC-06:00) Central America', + 'US/Central' => '(UTC-06:00) Central Time (US & Canada)', + 'America/Guadalajara' => '(UTC-06:00) Guadalajara', + 'America/Mexico_City' => '(UTC-06:00) Mexico City', + 'America/Monterrey' => '(UTC-06:00) Monterrey', + 'Canada/Saskatchewan' => '(UTC-06:00) Saskatchewan', + 'America/Bogota' => '(UTC-05:00) Bogota', + 'US/Eastern' => '(UTC-05:00) Eastern Time (US & Canada)', + 'US/East-Indiana' => '(UTC-05:00) Indiana (East)', + 'America/Lima' => '(UTC-05:00) Lima', + 'America/Quito' => '(UTC-05:00) Quito', + 'Canada/Atlantic' => '(UTC-04:00) Atlantic Time (Canada)', + 'America/New_York' => '(UTC-04:00) New York', + 'America/Caracas' => '(UTC-04:30) Caracas', + 'America/La_Paz' => '(UTC-04:00) La Paz', + 'America/Santiago' => '(UTC-04:00) Santiago', + 'America/Santo_Domingo' => '(UTC-04:00) Santo Domingo', + 'Canada/Newfoundland' => '(UTC-03:30) Newfoundland', + 'America/Sao_Paulo' => '(UTC-03:00) Brasilia', + 'America/Argentina/Buenos_Aires' => '(UTC-03:00) Buenos Aires', + 'America/Argentina/GeorgeTown' => '(UTC-03:00) Georgetown', + 'America/Godthab' => '(UTC-03:00) Greenland', + 'America/Noronha' => '(UTC-02:00) Mid-Atlantic', + 'Atlantic/Azores' => '(UTC-01:00) Azores', + 'Atlantic/Cape_Verde' => '(UTC-01:00) Cape Verde Is.', + 'Africa/Casablanca' => '(UTC+00:00) Casablanca', + 'Europe/Edinburgh' => '(UTC+00:00) Edinburgh', + 'Etc/Greenwich' => '(UTC+00:00) Greenwich Mean Time : Dublin', + 'Europe/Lisbon' => '(UTC+00:00) Lisbon', + 'Europe/London' => '(UTC+00:00) London', + 'Africa/Monrovia' => '(UTC+00:00) Monrovia', + 'UTC' => '(UTC+00:00) UTC', + 'Europe/Amsterdam' => '(UTC+01:00) Amsterdam', + 'Europe/Belgrade' => '(UTC+01:00) Belgrade', + 'Europe/Berlin' => '(UTC+01:00) Berlin', + 'Europe/Bern' => '(UTC+01:00) Bern', + 'Europe/Bratislava' => '(UTC+01:00) Bratislava', + 'Europe/Brussels' => '(UTC+01:00) Brussels', + 'Europe/Budapest' => '(UTC+01:00) Budapest', + 'Europe/Copenhagen' => '(UTC+01:00) Copenhagen', + 'Europe/Ljubljana' => '(UTC+01:00) Ljubljana', + 'Europe/Madrid' => '(UTC+01:00) Madrid', + 'Europe/Paris' => '(UTC+01:00) Paris', + 'Europe/Prague' => '(UTC+01:00) Prague', + 'Europe/Rome' => '(UTC+01:00) Rome', + 'Europe/Sarajevo' => '(UTC+01:00) Sarajevo', + 'Europe/Skopje' => '(UTC+01:00) Skopje', + 'Europe/Stockholm' => '(UTC+01:00) Stockholm', + 'Europe/Vienna' => '(UTC+01:00) Vienna', + 'Europe/Warsaw' => '(UTC+01:00) Warsaw', + 'Africa/Lagos' => '(UTC+01:00) West Central Africa', + 'Europe/Zagreb' => '(UTC+01:00) Zagreb', + 'Europe/Athens' => '(UTC+02:00) Athens', + 'Europe/Bucharest' => '(UTC+02:00) Bucharest', + 'Africa/Cairo' => '(UTC+02:00) Cairo', + 'Africa/Harare' => '(UTC+02:00) Harare', + 'Europe/Helsinki' => '(UTC+02:00) Helsinki', + 'Europe/Istanbul' => '(UTC+02:00) Istanbul', + 'Asia/Jerusalem' => '(UTC+02:00) Jerusalem', + 'Europe/Kyiv' => '(UTC+02:00) Kyiv', + 'Africa/Johannesburg' => '(UTC+02:00) Pretoria', + 'Europe/Riga' => '(UTC+02:00) Riga', + 'Europe/Sofia' => '(UTC+02:00) Sofia', + 'Europe/Tallinn' => '(UTC+02:00) Tallinn', + 'Europe/Vilnius' => '(UTC+02:00) Vilnius', + 'Asia/Baghdad' => '(UTC+03:00) Baghdad', + 'Asia/Kuwait' => '(UTC+03:00) Kuwait', + 'Europe/Minsk' => '(UTC+03:00) Minsk', + 'Africa/Nairobi' => '(UTC+03:00) Nairobi', + 'Asia/Riyadh' => '(UTC+03:00) Riyadh', + 'Europe/Volgograd' => '(UTC+03:00) Volgograd', + 'Asia/Tehran' => '(UTC+03:30) Tehran', + 'Asia/Abu_Dhabi' => '(UTC+04:00) Abu Dhabi', + 'Asia/Baku' => '(UTC+04:00) Baku', + 'Europe/Moscow' => '(UTC+04:00) Moscow', + 'Asia/Muscat' => '(UTC+04:00) Muscat', + 'Europe/St_Petersburg' => '(UTC+04:00) St. Petersburg', + 'Asia/Tbilisi' => '(UTC+04:00) Tbilisi', + 'Asia/Yerevan' => '(UTC+04:00) Yerevan', + 'Asia/Kabul' => '(UTC+04:30) Kabul', + 'Asia/Islamabad' => '(UTC+05:00) Islamabad', + 'Asia/Karachi' => '(UTC+05:00) Karachi', + 'Asia/Tashkent' => '(UTC+05:00) Tashkent', + 'Asia/Calcutta' => '(UTC+05:30) Chennai', + 'Asia/Kolkata' => '(UTC+05:30) Kolkata', + 'Asia/Mumbai' => '(UTC+05:30) Mumbai', + 'Asia/New_Delhi' => '(UTC+05:30) New Delhi', + 'Asia/Sri_Jayawardenepura' => '(UTC+05:30) Sri Jayawardenepura', + 'Asia/Katmandu' => '(UTC+05:45) Kathmandu', + 'Asia/Almaty' => '(UTC+06:00) Almaty', + 'Asia/Astana' => '(UTC+06:00) Astana', + 'Asia/Dhaka' => '(UTC+06:00) Dhaka', + 'Asia/Yekaterinburg' => '(UTC+06:00) Ekaterinburg', + 'Asia/Rangoon' => '(UTC+06:30) Rangoon', + 'Asia/Bangkok' => '(UTC+07:00) Bangkok', + 'Asia/Hanoi' => '(UTC+07:00) Hanoi', + 'Asia/Jakarta' => '(UTC+07:00) Jakarta', + 'Asia/Novosibirsk' => '(UTC+07:00) Novosibirsk', + 'Asia/Beijing' => '(UTC+08:00) Beijing', + 'Asia/Chongqing' => '(UTC+08:00) Chongqing', + 'Asia/Hong_Kong' => '(UTC+08:00) Hong Kong', + 'Asia/Krasnoyarsk' => '(UTC+08:00) Krasnoyarsk', + 'Asia/Kuala_Lumpur' => '(UTC+08:00) Kuala Lumpur', + 'Australia/Perth' => '(UTC+08:00) Perth', + 'Asia/Singapore' => '(UTC+08:00) Singapore', + 'Asia/Taipei' => '(UTC+08:00) Taipei', + 'Asia/Ulan_Bator' => '(UTC+08:00) Ulaan Bataar', + 'Asia/Urumqi' => '(UTC+08:00) Urumqi', + 'Asia/Irkutsk' => '(UTC+09:00) Irkutsk', + 'Asia/Osaka' => '(UTC+09:00) Osaka', + 'Asia/Sapporo' => '(UTC+09:00) Sapporo', + 'Asia/Seoul' => '(UTC+09:00) Seoul', + 'Asia/Tokyo' => '(UTC+09:00) Tokyo', + 'Australia/Adelaide' => '(UTC+09:30) Adelaide', + 'Australia/Darwin' => '(UTC+09:30) Darwin', + 'Australia/Brisbane' => '(UTC+10:00) Brisbane', + 'Australia/Canberra' => '(UTC+10:00) Canberra', + 'Pacific/Guam' => '(UTC+10:00) Guam', + 'Australia/Hobart' => '(UTC+10:00) Hobart', + 'Australia/Melbourne' => '(UTC+10:00) Melbourne', + 'Pacific/Port_Moresby' => '(UTC+10:00) Port Moresby', + 'Australia/Sydney' => '(UTC+10:00) Sydney', + 'Asia/Yakutsk' => '(UTC+10:00) Yakutsk', + 'Asia/Vladivostok' => '(UTC+11:00) Vladivostok', + 'Pacific/Auckland' => '(UTC+12:00) Auckland', + 'Pacific/Fiji' => '(UTC+12:00) Fiji', + 'Pacific/Kwajalein' => '(UTC+12:00) International Date Line West', + 'Asia/Kamchatka' => '(UTC+12:00) Kamchatka', + 'Asia/Magadan' => '(UTC+12:00) Magadan', + 'Pacific/Marshall_Is' => '(UTC+12:00) Marshall Is.', + 'Asia/New_Caledonia' => '(UTC+12:00) New Caledonia', + 'Asia/Solomon_Is' => '(UTC+12:00) Solomon Is.', + 'Pacific/Wellington' => '(UTC+12:00) Wellington', + 'Pacific/Tongatapu' => '(UTC+13:00) Nuku\'alofa' + ], + 'placeholder' => 'Choose a timezone...' + ]), + 'locked' => 1, + 'sort' => 11, + 'width' => 'half', + 'required' => 1 + ], + [ + 'collection' => 'directus_users', + 'field' => 'locale', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'language', + 'options' => json_encode([ + 'limit' => true + ]), + 'locked' => 1, + 'sort' => 12, + 'width' => 'half', + 'required' => 0 + ], + [ + 'collection' => 'directus_users', + 'field' => 'avatar', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_FILE, + 'interface' => 'file', + 'locked' => 1, + 'sort' => 13 + ], + [ + 'collection' => 'directus_users', + 'field' => 'theme', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'radio-buttons', + 'options' => json_encode([ + 'format' => true, + 'choices' => [ + 'auto' => 'Auto', + 'light' => 'Light', + 'dark' => 'Dark' + ] + ]), + 'locked' => 1, + 'readonly' => 0, + 'sort' => 14 + ], + [ + 'collection' => 'directus_users', + 'field' => '2fa_secret', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => '2fa-secret', + 'locked' => 1, + 'readonly' => 1, + 'sort' => 15 + ], + [ + 'collection' => 'directus_users', + 'field' => 'locale_options', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, + 'interface' => 'json', + 'locked' => 1, + 'hidden_browse' => 1, + 'hidden_detail' => 1, + 'sort' => 16 + ], + [ + 'collection' => 'directus_users', + 'field' => 'token', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'hidden_detail' => 1, + 'hidden_browse' => 1, + 'sort' => 17 + ], + [ + 'collection' => 'directus_users', + 'field' => 'last_access_on', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_DATETIME, + 'interface' => 'datetime', + 'locked' => 1, + 'readonly' => 1, + 'hidden_detail' => 1, + 'sort' => 18 + ], + [ + 'collection' => 'directus_users', + 'field' => 'last_page', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'readonly' => 1, + 'hidden_detail' => 1, + 'hidden_browse' => 1, + 'sort' => 19 + ], + [ + 'collection' => 'directus_users', + 'field' => 'external_id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'locked' => 1, + 'readonly' => 1, + 'hidden_detail' => 20 + ], + + // --------------------------------------------------------------------- + // directus_user_sessions + [ + 'collection' => 'directus_user_sessions', + 'field' => 'id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'primary-key', + 'locked' => 1, + 'required' => 1, + 'hidden_detail' => 1 + ], + [ + 'collection' => 'directus_user_sessions', + 'field' => 'user', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_USER, + 'required' => 1, + 'interface' => 'user' + ], + [ + 'collection' => 'directus_user_sessions', + 'field' => 'token_type', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input' + ], + [ + 'collection' => 'directus_user_sessions', + 'field' => 'token', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input' + ], + [ + 'collection' => 'directus_user_sessions', + 'field' => 'ip_address', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input' + ], + [ + 'collection' => 'directus_user_sessions', + 'field' => 'user_agent', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input' + ], + [ + 'collection' => 'directus_user_sessions', + 'field' => 'created_on', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_DATETIME, + 'interface' => 'datetime' + ], + [ + 'collection' => 'directus_user_sessions', + 'field' => 'token_expired_at', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_DATETIME, + 'interface' => 'datetime' + ], + + // --------------------------------------------------------------------- + // directus_webhooks + [ + 'collection' => 'directus_webhooks', + 'field' => 'id', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_INTEGER, + 'interface' => 'primary-key', + 'locked' => 1, + 'required' => 1, + 'hidden_detail' => 1 + ], + [ + 'collection' => 'directus_webhooks', + 'field' => 'status', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STATUS, + 'interface' => 'status', + 'options' => json_encode([ + 'status_mapping' => [ + 'active' => [ + 'name' => 'Active', + 'value' => 'active', + 'text_color' => 'white', + 'background_color' => 'green', + 'browse_subdued' => false, + 'browse_badge' => true, + 'soft_delete' => false, + 'published' => true, + ], + 'inactive' => [ + 'name' => 'Inactive', + 'value' => 'inactive', + 'text_color' => 'white', + 'background_color' => 'blue-grey', + 'browse_subdued' => true, + 'browse_badge' => true, + 'soft_delete' => false, + 'published' => false, + ] + ] + ]), + 'locked' => 1, + 'width' => 'full', + 'sort' => 1 + ], + [ + 'collection' => 'directus_webhooks', + 'field' => 'http_action', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'dropdown', + 'required' => 1, + 'options' => json_encode([ + 'choices' => [ + 'get' => 'GET', + 'post' => 'POST' + ] + ]), + 'locked' => 1, + 'width' => 'half-space', + 'sort' => 2 + ], + [ + 'collection' => 'directus_webhooks', + 'field' => 'url', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'text-input', + 'options' => json_encode([ + 'placeholder' => 'https://example.com', + 'iconRight' => 'link' + ]), + 'required' => 1, + 'locked' => 1, + 'width' => 'full', + 'note' => '', + 'sort' => 3 + ], + [ + 'collection' => 'directus_webhooks', + 'field' => 'collection', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'collections', + 'required' => 1, + 'locked' => 1, + 'width' => 'half', + 'note' => '', + 'sort' => 4 + ], + [ + 'collection' => 'directus_webhooks', + 'field' => 'directus_action', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'dropdown', + 'required' => 1, + 'options' => json_encode([ + 'choices' => [ + 'item.create:after' => 'Create', + 'item.update:after' => 'Update', + 'item.delete:after' => 'Delete', + ] + ]), + 'locked' => 1, + 'width' => 'half', + 'note' => '', + 'sort' => 5 + ], + [ + 'collection' => 'directus_webhooks', + 'field' => 'info', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_ALIAS, + 'interface' => 'divider', + 'options' => json_encode([ + 'style' => 'medium', + 'title' => 'How Webhooks Work', + 'hr' => true, + 'margin' => false, + 'description' => 'When the selected action occurs for the selected collection, Directus will send an HTTP request to the above URL.' + ]), + 'locked' => 1, + 'width' => 'full', + 'hidden_browse' => 1, + 'sort' => 6 + ], + ]; + + // ------------------------------------------------------------------------- + // Add the data to the table + // ------------------------------------------------------------------------- + $fieldsTable->insert($data); + + // ------------------------------------------------------------------------- + // Save changes to table + // ------------------------------------------------------------------------- + $fieldsTable->save(); + } +} diff --git a/migrations/upgrades/schemas/20190914095509_update_directus_user_sessions.php b/migrations/upgrades/schemas/20190914095509_update_directus_user_sessions.php deleted file mode 100644 index 35c826317a..0000000000 --- a/migrations/upgrades/schemas/20190914095509_update_directus_user_sessions.php +++ /dev/null @@ -1,48 +0,0 @@ -table('directus_user_sessions'); - if (!$table->hasColumn('token_type')) { - $table->addColumn('token_type', 'string', [ - 'null' => true, - 'default' => null - ]); - } - - if (!$table->hasColumn('token_expired_at')) { - $table->addColumn('token_expired_at', 'datetime', [ - 'null' => true, - 'default' => null - ]); - } - - $table->save(); - } -} diff --git a/migrations/upgrades/schemas/20191001092213_add_project_settings.php b/migrations/upgrades/schemas/20191001092213_add_project_settings.php deleted file mode 100644 index ffe9e0005c..0000000000 --- a/migrations/upgrades/schemas/20191001092213_add_project_settings.php +++ /dev/null @@ -1,61 +0,0 @@ -execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'width' => 'half' - ], - ['collection' => 'directus_settings', 'field' => 'file_naming'] - )); - - // Update width of file nameing option - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'width' => 'half' - ], - ['collection' => 'directus_settings', 'field' => 'login_attempts_allowed'] - )); - - - $settings = [ - 'project_icon' => [ - 'interface' => 'icon', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, - 'width' => 'half', - ], - 'project_image' => [ - 'interface' => 'file', - 'width' => 'half', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_FILE, - ] - ]; - foreach ($settings as $field => $options) { - $this->addField($field, $options); - } - } - - protected function addField($field, $options) - { - $collection = 'directus_settings'; - $checkSql = sprintf('SELECT 1 FROM `directus_fields` WHERE `collection` = "%s" AND `field` = "%s";', $collection, $field); - $result = $this->query($checkSql)->fetch(); - - if (!$result) { - $insertSqlFormat = 'INSERT INTO `directus_fields` (`collection`, `field`, `type`, `interface`,`width`) VALUES ("%s", "%s", "%s", "%s", "%s");'; - $insertSql = sprintf($insertSqlFormat, $collection, $field, $options['type'], $options['interface'], $options['width']); - $this->execute($insertSql); - } - } -} diff --git a/migrations/upgrades/schemas/20191002070945_rename_settings.php b/migrations/upgrades/schemas/20191002070945_rename_settings.php deleted file mode 100644 index 0e3c103d3c..0000000000 --- a/migrations/upgrades/schemas/20191002070945_rename_settings.php +++ /dev/null @@ -1,31 +0,0 @@ -execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'field' => 'project_color' - ], - ['collection' => 'directus_settings', 'field' => 'color'] - )); - - // Update the key in directus_settings collection - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_settings', - [ - 'key' => 'project_color' - ], - ['key' => 'color'] - )); - } -} diff --git a/migrations/upgrades/schemas/20191007113144_update_type_for_uploaded_by_directus_files.php b/migrations/upgrades/schemas/20191007113144_update_type_for_uploaded_by_directus_files.php deleted file mode 100644 index 40847ce4a7..0000000000 --- a/migrations/upgrades/schemas/20191007113144_update_type_for_uploaded_by_directus_files.php +++ /dev/null @@ -1,20 +0,0 @@ -execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'type' => \Directus\Database\Schema\DataTypes::TYPE_USER_CREATED, - 'interface' => 'user-created' - ], - ['collection' => 'directus_files', 'field' => 'uploaded_by'] - )); - } -} diff --git a/migrations/upgrades/schemas/20191105063515_update_general_setting_variabe_name.php b/migrations/upgrades/schemas/20191105063515_update_general_setting_variabe_name.php deleted file mode 100644 index 695757ccb1..0000000000 --- a/migrations/upgrades/schemas/20191105063515_update_general_setting_variabe_name.php +++ /dev/null @@ -1,100 +0,0 @@ -execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'field' => 'project_logo' - ], - ['collection' => 'directus_settings', 'field' => 'logo'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_settings', - [ - 'key' => 'project_logo' - ], - ['key' => 'logo'] - )); - - // Update the interface of project_icon from icon to file and rename it. - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'field' => 'project_foreground', - 'type' => \Directus\Database\Schema\DataTypes::TYPE_FILE, - 'interface' => 'file' - ], - ['collection' => 'directus_settings', 'field' => 'project_icon'] - )); - - // Need to delete the project_icon as this migration will change the interface to file and the icon will contain the string - $result = $this->query('SELECT 1 FROM `directus_settings` WHERE `key` = "project_icon";')->fetch(); - - if ($result) { - $this->execute('DELETE FROM `directus_settings` where `key` = "project_icon";'); - } - - // Rename project_image - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'field' => 'project_background' - ], - ['collection' => 'directus_settings', 'field' => 'project_image'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_settings', - [ - 'key' => 'project_background' - ], - ['key' => 'project_image'] - )); - - $result = $this->query('SELECT 1 FROM `directus_fields` WHERE `field` = "app_url";')->fetch(); - - if ($result) { - $this->execute('DELETE FROM `directus_fields` where `field` = "app_url";'); - } - - $result = $this->query('SELECT 1 FROM `directus_settings` WHERE `key` = "app_url";')->fetch(); - - if ($result) { - $this->execute('DELETE FROM `directus_settings` where `key` = "app_url";'); - } - } -} diff --git a/migrations/upgrades/schemas/20191112161523_add_locale_and_telemetry_to_settings_table.php b/migrations/upgrades/schemas/20191112161523_add_locale_and_telemetry_to_settings_table.php deleted file mode 100644 index 04eae23283..0000000000 --- a/migrations/upgrades/schemas/20191112161523_add_locale_and_telemetry_to_settings_table.php +++ /dev/null @@ -1,32 +0,0 @@ - [ - 'type' => 'string', - 'interface' => 'language' - ], - 'telemetry' => [ - 'type' => 'boolean', - 'interface' => 'toggle' - ] - ]; - foreach ($settings as $field => $options) { - $this->addField($field, $options['type'], $options['interface']); - } - } - protected function addField($field, $type, $interface) - { - $collection = 'directus_settings'; - $checkSql = sprintf('SELECT 1 FROM `directus_fields` WHERE `collection` = "%s" AND `field` = "%s";', $collection, $field); - $result = $this->query($checkSql)->fetch(); - if (!$result) { - $insertSqlFormat = 'INSERT INTO `directus_fields` (`collection`, `field`, `type`, `interface`) VALUES ("%s", "%s", "%s", "%s");'; - $insertSql = sprintf($insertSqlFormat, $collection, $field, $type, $interface); - $this->execute($insertSql); - } - } -} \ No newline at end of file diff --git a/migrations/upgrades/schemas/20191112175432_remove_activity_seen_fields.php b/migrations/upgrades/schemas/20191112175432_remove_activity_seen_fields.php deleted file mode 100644 index 5ed8e97d47..0000000000 --- a/migrations/upgrades/schemas/20191112175432_remove_activity_seen_fields.php +++ /dev/null @@ -1,48 +0,0 @@ -query('SELECT 1 FROM `directus_fields` WHERE `collection` = "directus_activity_seen"')->fetch(); - - if ($result) { - $this->execute('DELETE FROM `directus_fields` WHERE `collection` = "directus_activity_seen"'); - } - - $result = $this->query('SELECT 1 FROM `directus_relations` WHERE `collection_many` = "directus_activity_seen"')->fetch(); - - if ($result) { - $this->execute('DELETE FROM `directus_relations` WHERE `collection_many` = "directus_activity_seen"'); - } - - - $this->execute('DROP TABLE IF EXISTS directus_activity_seen'); - - } -} diff --git a/migrations/upgrades/schemas/20191113083711_update_current_migrations.php b/migrations/upgrades/schemas/20191113083711_update_current_migrations.php deleted file mode 100644 index 9e028af84e..0000000000 --- a/migrations/upgrades/schemas/20191113083711_update_current_migrations.php +++ /dev/null @@ -1,665 +0,0 @@ -getContainer()->get('config'); - $dbName = $config->get('database.name'); - - - // Fields Table - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'iconRight' => 'change_history' - ]), - 'width' => 'full' - ], - ['collection' => 'directus_activity', 'field' => 'action'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'iconRight' => 'list_alt' - ]) - ], - ['collection' => 'directus_activity', 'field' => 'collection'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'iconRight' => 'link' - ]) - ], - ['collection' => 'directus_activity', 'field' => 'item'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'iconRight' => 'account_circle' - ]) - ], - ['collection' => 'directus_activity', 'field' => 'action_by'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'showRelative' => true, - 'iconRight' => 'calendar_today' - ]) - ], - ['collection' => 'directus_activity', 'field' => 'action_on'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'showRelative' => true, - 'iconRight' => 'edit' - ]) - ], - ['collection' => 'directus_activity', 'field' => 'edited_on'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'showRelative' => true, - 'iconRight' => 'delete_outline' - ]) - ], - ['collection' => 'directus_activity', 'field' => 'comment_deleted_on'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'iconRight' => 'my_location' - ]) - ], - ['collection' => 'directus_activity', 'field' => 'ip'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'iconRight' => 'devices_other' - ]), - 'width' => 'full' - ], - ['collection' => 'directus_activity', 'field' => 'user_agent'] - )); - - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'placeholder' => 'Enter a keyword then hit enter...' - ]), - ], - ['collection' => 'directus_files', 'field' => 'tags'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'toolbar' => ['bold','italic','underline','link','code'] - ]), - ], - ['collection' => 'directus_files', 'field' => 'description'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'width' => 'full' - ], - ['collection' => 'directus_files', 'field' => 'metadata'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'iconRight' => 'title' - ]), - 'width' => 'half', - 'note' => 'Logo in the top-left of the App (40x40)', - ], - ['collection' => 'directus_settings', 'field' => 'project_name'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'note' => 'A 40x40 brand logo, ideally a white SVG/PNG', - ], - ['collection' => 'directus_settings', 'field' => 'project_logo'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'iconRight' => 'keyboard_tab' - ]), - 'note' => 'Default item count in API and App responses', - 'sort' => 11 - ], - ['collection' => 'directus_settings', 'field' => 'default_limit'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'note' => 'NULL values are sorted last', - ], - ['collection' => 'directus_settings', 'field' => 'sort_null_last'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'iconRight' => 'timer' - ]), - 'note' => 'Minutes before idle users are signed out', - 'sort' => 22 - ], - ['collection' => 'directus_settings', 'field' => 'auto_sign_out'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'placeholder' => 'Allowed dimensions for thumbnails (eg: 200x200)' - ]), - 'width' => 'full', - 'sort' => 34 - ], - ['collection' => 'directus_settings', 'field' => 'thumbnail_dimensions'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'note' => 'Allowed qualities for thumbnails', - 'sort' => 35 - ], - ['collection' => 'directus_settings', 'field' => 'thumbnail_quality_tags'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'note' => 'Defines how the thumbnail will be generated based on the requested dimensions', - 'sort' => 36 - ], - ['collection' => 'directus_settings', 'field' => 'thumbnail_actions'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'iconRight' => 'broken_image' - ]), - 'locked' => 1, - 'width' => 'full', - 'note' => 'A fallback image used when thumbnail generation fails', - 'sort' => 37 - ], - ['collection' => 'directus_settings', 'field' => 'thumbnail_not_found_location'] - )); - - $result = $this->query('SELECT 1 FROM `directus_fields` WHERE `collection` = "directus_settings" and `field` = "thumbnail_cache_ttl";')->fetch(); - - if ($result) { - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'iconRight' => 'cached' - ]), - 'required' => 1, - 'note' => 'Seconds before browsers re-fetch thumbnails', - 'sort' => 38 - ], - ['collection' => 'directus_settings', 'field' => 'thumbnail_cache_ttl'] - )); - } - - $result = $this->query('SELECT 1 FROM `directus_fields` WHERE `collection` = "directus_settings" and `field` = "youtube_api";')->fetch(); - - if ($result) { - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'iconRight' => 'videocam' - ]), - 'width' => 'half', - 'note' => 'Allows fetching more YouTube Embed info', - 'sort' => 39 - ], - ['collection' => 'directus_settings', 'field' => 'youtube_api'] - )); - } - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'required' => 0 - ], - ['collection' => 'directus_users', 'field' => 'locale'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'iconRight' => 'account_circle' - ]), - ], - ['collection' => 'directus_users', 'field' => 'first_name'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'iconRight' => 'account_circle' - ]), - ], - ['collection' => 'directus_users', 'field' => 'last_name'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'iconRight' => 'alternate_email' - ]), - ], - ['collection' => 'directus_users', 'field' => 'email'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'iconRight' => 'location_city' - ]), - ], - ['collection' => 'directus_users', 'field' => 'company'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'iconRight' => 'text_fields' - ]), - ], - ['collection' => 'directus_users', 'field' => 'title'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'sort' => 15 - ], - ['collection' => 'directus_users', 'field' => 'locale_options'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'sort' => 16 - ], - ['collection' => 'directus_users', 'field' => 'token'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'sort' => 17 - ], - ['collection' => 'directus_users', 'field' => 'last_access_on'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'sort' => 18 - ], - ['collection' => 'directus_users', 'field' => 'last_page'] - )); - - - $result = $this->query('SELECT 1 FROM `directus_fields` WHERE `collection` = "directus_users" and `field` = "last_login";')->fetch(); - - if ($result) { - $this->execute('DELETE FROM `directus_fields` where `collection` = "directus_users" and `field` = "last_login";'); - } - - $result = $this->query('SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = "'.$dbName.'" AND TABLE_NAME = "directus_users" AND COLUMN_NAME = "last_login"')->fetch(); - - if ($result) { - $this->execute('ALTER TABLE `directus_users` DROP last_login;'); - } - - $result = $this->query('SELECT 1 FROM `directus_fields` WHERE `collection` = "directus_users" and `field` = "invite_token";')->fetch(); - - if ($result) { - $this->execute('DELETE FROM `directus_fields` where `collection` = "directus_users" and `field` = "invite_token";'); - } - - $result = $this->query('SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = "'.$dbName.'" AND TABLE_NAME = "directus_users" AND COLUMN_NAME = "invite_token"')->fetch(); - - if ($result) { - $this->execute('ALTER TABLE `directus_users` DROP invite_token;'); - } - - - $result = $this->query('SELECT 1 FROM `directus_fields` WHERE `collection` = "directus_users" and `field` = "invite_accepted";')->fetch(); - - if ($result) { - $this->execute('DELETE FROM `directus_fields` where `collection` = "directus_users" and `field` = "invite_accepted";'); - } - - $result = $this->query('SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = "'.$dbName.'" AND TABLE_NAME = "directus_users" AND COLUMN_NAME = "invite_accepted"')->fetch(); - - if ($result) { - $this->execute('ALTER TABLE `directus_users` DROP invite_accepted;'); - } - - - $result = $this->query('SELECT 1 FROM `directus_fields` WHERE `collection` = "directus_users" and `field` = "last_ip";')->fetch(); - - if ($result) { - $this->execute('DELETE FROM `directus_fields` where `collection` = "directus_users" and `field` = "last_ip";'); - } - - $result = $this->query('SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = "'.$dbName.'" AND TABLE_NAME = "directus_users" AND COLUMN_NAME = "last_ip"')->fetch(); - - if ($result) { - $this->execute('ALTER TABLE `directus_users` DROP last_ip;'); - } - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'limit' => true - ]), - 'width' => 'half', - 'note' => 'Default locale for Directus Users', - 'sort' => 7 - ], - ['collection' => 'directus_settings', 'field' => 'default_locale'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'hidden_browse' => 1, - ], - ['collection' => 'directus_settings', 'field' => 'data_divider'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'hidden_browse' => 1, - ], - ['collection' => 'directus_settings', 'field' => 'security_divider'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'hidden_browse' => 1, - ], - ['collection' => 'directus_settings', 'field' => 'files_divider'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'hidden_browse' => 1, - ], - ['collection' => 'directus_webhooks', 'field' => 'info'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'width' => 'half', - 'note' => 'Learn More', - 'sort' => 8 - ], - ['collection' => 'directus_settings', 'field' => 'telemetry'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'locked' => 1, - 'width' => 'full', - 'sort' => 1 - ], - ['collection' => 'directus_webhooks', 'field' => 'status'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'locked' => 1, - 'width' => 'half-space', - 'sort' => 2 - ], - ['collection' => 'directus_webhooks', 'field' => 'http_action'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'placeholder' => 'https://example.com', - 'iconRight' => 'link' - ]), - 'locked' => 1, - 'width' => 'full', - 'note' => '', - 'sort' => 3 - ], - ['collection' => 'directus_webhooks', 'field' => 'url'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'interface' => 'collections', - 'locked' => 1, - 'width' => 'half', - 'note' => '', - 'sort' => 4 - ], - ['collection' => 'directus_webhooks', 'field' => 'collection'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'locked' => 1, - 'width' => 'half', - 'note' => '', - 'sort' => 5 - ], - ['collection' => 'directus_webhooks', 'field' => 'directus_action'] - )); - - $result = $this->query('SELECT 1 FROM `directus_fields` WHERE `collection` = "directus_webhooks" and `field` = "info";')->fetch(); - - if (!$result) { - $options = json_encode([ - 'style' => 'medium', - 'title' => 'How Webhooks Work', - 'hr' => true, - 'margin' => false, - 'description' => 'When the selected action occurs for the selected collection, Directus will send an HTTP request to the above URL.' - ]); - - $this->execute("INSERT INTO `directus_fields` (`collection`, `field`, `type`, `interface`,`options`, `locked`, `width`, `sort`) VALUES ('directus_webhooks', 'info', '".\Directus\Database\Schema\DataTypes::TYPE_ALIAS."', 'divider', '".$options."', '1', 'full', '6');"); - } - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'status_mapping' => [ - 'active' => [ - 'name' => 'Active', - 'value' => 'active', - 'text_color' => 'white', - 'background_color' => 'green', - 'browse_subdued' => false, - 'browse_badge' => true, - 'soft_delete' => false, - 'published' => true, - ], - 'inactive' => [ - 'name' => 'Inactive', - 'value' => 'inactive', - 'text_color' => 'white', - 'background_color' => 'blue-grey', - 'browse_subdued' => true, - 'browse_badge' => true, - 'soft_delete' => false, - 'published' => false, - ] - ] - ]), - ], - ['collection' => 'directus_webhooks', 'field' => 'status'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'choices' => [ - 'get' => 'GET', - 'post' => 'POST' - ] - ]), - ], - ['collection' => 'directus_webhooks', 'field' => 'http_action'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'options' => json_encode([ - 'choices' => [ - 'item.create:after' => 'Create', - 'item.update:after' => 'Update', - 'item.delete:after' => 'Delete', - ] - ]), - ], - ['collection' => 'directus_webhooks', 'field' => 'directus_action'] - )); - - - // Role table - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_roles', - [ - 'description' => 'Controls what API data is publicly available without authenticating' - ], - ['name' => 'public'] - )); - - // Settings Table - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_settings', - [ - 'value' => '10080' - ], - ['key' => 'auto_sign_out'] - )); - - - } -} diff --git a/migrations/upgrades/schemas/20191114095051_update_user_role_type.php b/migrations/upgrades/schemas/20191114095051_update_user_role_type.php deleted file mode 100644 index e6e1a2c915..0000000000 --- a/migrations/upgrades/schemas/20191114095051_update_user_role_type.php +++ /dev/null @@ -1,86 +0,0 @@ -execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'interface' => 'one-to-many' - ], - ['collection' => 'directus_roles', 'field' => 'users'] - )); - - $this->execute(\Directus\phinx_update( - $this->getAdapter(), - 'directus_fields', - [ - 'field' => 'role', - 'type' => 'm2o' - ], - ['collection' => 'directus_users', 'field' => 'roles'] - )); - - $result = $this->query('SELECT 1 FROM `directus_fields` WHERE `collection` = "directus_user_roles";')->fetch(); - - if ($result) { - $this->execute('DELETE FROM `directus_fields` where `collection` = "directus_user_roles";'); - } - - $config = \Directus\Application\Application::getInstance()->getContainer()->get('config'); - $dbName = $config->get('database.name'); - - - $result = $this->query('SELECT * FROM information_schema.COLUMNS WHERE TABLE_SCHEMA = "'.$dbName.'" AND TABLE_NAME = "directus_users" AND COLUMN_NAME = "role"')->fetch(); - - if(!$result){ - $this->execute('ALTER TABLE `directus_users` ADD COLUMN `role` INT;'); - } - - $result = $this->query('SELECT 1 FROM `directus_relations` WHERE `collection_many` = "directus_user_roles";')->fetch(); - - if ($result) { - $this->execute('DELETE FROM `directus_relations` where `collection_many` = "directus_user_roles";'); - } - - $this->execute("INSERT INTO `directus_relations` (`collection_many`, `field_many`, `collection_one`, `field_one`) VALUES ('directus_users', 'role','directus_roles','users');"); - - $tableExist = $this->query('SELECT TABLE_NAME FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_SCHEMA = "'.$dbName.'" AND TABLE_NAME = "directus_user_roles"')->fetch(); - - if($tableExist){ - $stmt = $this->query("SELECT * FROM `directus_user_roles`"); - while($row = $stmt->fetch(PDO::FETCH_ASSOC)){ - $this->execute('UPDATE `directus_users` SET `role` = '.$row['role'].' where id = '.$row['user'].';'); - } - } - - $this->execute('DROP TABLE IF EXISTS directus_user_roles'); - } -} diff --git a/migrations/upgrades/schemas/20191118181240_add_theme_field_for_user.php b/migrations/upgrades/schemas/20191118181240_add_theme_field_for_user.php deleted file mode 100644 index 67f819784d..0000000000 --- a/migrations/upgrades/schemas/20191118181240_add_theme_field_for_user.php +++ /dev/null @@ -1,56 +0,0 @@ -table('directus_users'); - if (!$table->hasColumn('theme')) { - $table->addColumn('theme', 'string', [ - 'limit' => 255, - 'null' => true, - 'default' => null - ]); - - $table->save(); - } - - $result = $this->query('SELECT 1 FROM `directus_fields` WHERE `collection` = "directus_users" AND `field` = "theme"')->fetch(); - - if (!$result) { - $options = json_encode([ - 'format' => true, - 'choices' => [ - 'auto' => 'Auto', - 'light' => 'Light', - 'dark' => 'Dark' - ] - ]); - $this->execute("INSERT INTO `directus_fields` (`collection`, `field`, `type`, `interface`, `options`, `locked`, `readonly`, `sort`) VALUES ('directus_users', 'theme', 'string', 'radio-buttons', '".$options."', 1,0 , 14);"); - } - } -} diff --git a/migrations/upgrades/seeds/.gitkeep b/public/extensions/custom/modules/.gitkeep similarity index 100% rename from migrations/upgrades/seeds/.gitkeep rename to public/extensions/custom/modules/.gitkeep diff --git a/public/thumbnail/.htaccess b/public/thumbnail/.htaccess deleted file mode 100644 index 6b419793d5..0000000000 --- a/public/thumbnail/.htaccess +++ /dev/null @@ -1,2 +0,0 @@ -RewriteEngine On -RewriteRule (.*) index.php [L] diff --git a/public/thumbnail/index.php b/public/thumbnail/index.php deleted file mode 100644 index 0dafda9cd9..0000000000 --- a/public/thumbnail/index.php +++ /dev/null @@ -1,90 +0,0 @@ - [ - 'error' => 8, - 'message' => 'API Project Configuration Not Found: ' . $projectName - ] - ]); - exit; -} - -$settings = \Directus\get_directus_thumbnail_settings(); -$timeToLive = \Directus\array_get($settings, 'thumbnail_cache_ttl', 86400); -try { - - parse_str($_SERVER['QUERY_STRING'], $queryParams); - - // if the thumb already exists, return it - $thumbnailer = new Thumbnailer( - $app->getContainer()->get('filesystem'), - $app->getContainer()->get('filesystem_thumb'), - $settings, - urldecode(\Directus\get_virtual_path()), - $queryParams - ); - - $image = $thumbnailer->get(); - - if (!$image) { - // now we can create the thumb - switch ($thumbnailer->action) { - // http://image.intervention.io/api/resize - case 'contain': - $image = $thumbnailer->contain(); - break; - // http://image.intervention.io/api/fit - case 'crop': - default: - $image = $thumbnailer->crop(); - } - } - - header('HTTP/1.1 200 OK'); - header('Content-type: ' . $thumbnailer->getThumbnailMimeType()); - header("Pragma: cache"); - header('Cache-Control: max-age=' . $timeToLive); - header("Access-Control-Allow-Origin: *"); - header("Access-Control-Allow-Methods: PUT, GET, POST, DELETE, OPTIONS"); - header("Access-Control-Allow-Headers: Access-Control-Allow-Headers,Content-Type"); - header('Last-Modified: ' . gmdate('D, d M Y H:i:s \G\M\T', time())); - header('Expires: ' . gmdate('D, d M Y H:i:s \G\M\T', time() + $timeToLive)); - echo $image; - exit(0); -} catch (Exception $e) { - $filePath = ArrayUtils::get($settings, 'thumbnail_not_found_location'); - if (is_string($filePath) && !empty($filePath) && $filePath[0] !== '/') { - $filePath = $basePath . '/' . $filePath; - } - - // TODO: Throw message if the error is a invalid configuration - if (file_exists($filePath)) { - $mime = image_type_to_mime_type(exif_imagetype($filePath)); - - // TODO: Do we need to cache non-existing files? - header('Content-type: ' . $mime); - header("Pragma: cache"); - header('Cache-Control: max-age=' . $timeToLive); - header('Last-Modified: ' . gmdate('D, d M Y H:i:s \G\M\T', time())); - header('Expires: ' . gmdate('D, d M Y H:i:s \G\M\T', time() + $timeToLive)); - echo file_get_contents($filePath); - } else { - http_response_code(404); - } - - exit(0); -} diff --git a/public/extensions/custom/pages/.gitkeep b/public/uploads/.gitkeep similarity index 100% rename from public/extensions/custom/pages/.gitkeep rename to public/uploads/.gitkeep diff --git a/public/uploads/_/originals/.gitkeep b/public/uploads/_/originals/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/public/uploads/_/originals/.htaccess b/public/uploads/_/originals/.htaccess deleted file mode 100644 index df5cb35238..0000000000 --- a/public/uploads/_/originals/.htaccess +++ /dev/null @@ -1,24 +0,0 @@ - - ExpiresActive On - ExpiresDefault "access 1 year" - - - - order allow,deny - deny from all - - - - - Header set Access-Control-Allow-Origin "*" - Header set Access-Control-Allow-Methods "PUT, GET, POST, DELETE, OPTIONS" - Header set Access-Control-Allow-Headers "Access-Control-Allow-Headers,Content-Type" - - - -# Respond with 404 if the file doesn't exists -# Before the API mod_rewrite catches the request - - RewriteCond %{REQUEST_FILENAME} !-f - RewriteRule .* - [L,R=404] - diff --git a/public/uploads/_/thumbnails/.gitkeep b/public/uploads/_/thumbnails/.gitkeep deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/src/core/Directus/Application/Application.php b/src/core/Directus/Application/Application.php index cfcea8ac80..c6ab4d77a8 100644 --- a/src/core/Directus/Application/Application.php +++ b/src/core/Directus/Application/Application.php @@ -13,7 +13,7 @@ class Application extends App * * @var string */ - const DIRECTUS_VERSION = '8.0.0-rc.2'; + const DIRECTUS_VERSION = '8.0.0'; /** * NOT USED diff --git a/src/core/Directus/Application/CoreServicesProvider.php b/src/core/Directus/Application/CoreServicesProvider.php index 354a7bc7d3..761294c74a 100644 --- a/src/core/Directus/Application/CoreServicesProvider.php +++ b/src/core/Directus/Application/CoreServicesProvider.php @@ -70,6 +70,7 @@ use Slim\Views\Twig; use Zend\Db\TableGateway\TableGateway; use Directus\Api\Routes\Roles; +use function Directus\get_random_string; class CoreServicesProvider { @@ -125,8 +126,8 @@ protected function getLogger() // TODO: Move log configuration outside "slim app" settings $path = $container->get('path_base') . '/logs'; $config = $container->get('config'); - if ($config->has('settings.logger.path')) { - $path = $config->get('settings.logger.path'); + if ($config->has('logger.path')) { + $path = $config->get('logger.path'); } $pathIsStream = $path == 'php://stdout' || $path == 'php://stderr'; @@ -184,7 +185,7 @@ protected function getErrorHandler() $hookEmitter = $container['hook_emitter']; return new ErrorHandler($hookEmitter, [ - 'env' => $container->get('config')->get('app.env', 'development') + 'env' => $container->get('config')->get('env', 'development') ]); }; @@ -291,66 +292,8 @@ protected function getEmitter() return $payload; }, Emitter::P_HIGH); - $savesFile = function (Payload $payload, $replace = false) use ($container) { - $collectionName = $payload->attribute('collection_name'); - if ($collectionName !== SchemaManager::COLLECTION_FILES) { - return; - } - - if ($replace === true && !$payload->has('data')) { - return; - } - - // NOTE: "data" should be ignore if it isn't a string on update - if ($replace === true && !is_string($payload->get('data'))) { - $payload->remove('data'); - return; - } - - $data = $payload->getData(); - /** @var \Directus\Filesystem\Files $files */ - $files = $container->get('files'); - - $fileData = ArrayUtils::get($data, 'data'); - - $dataInfo = []; - if (is_a_url($fileData)) { - $dataInfo = $files->getLink($fileData); - // Set the URL payload data - $payload['data'] = ArrayUtils::get($dataInfo, 'data'); - $payload['filename'] = ArrayUtils::get($dataInfo, 'filename'); - } else if (!is_object($fileData)) { - $dataInfo = $files->getDataInfo($fileData); - } - - $type = ArrayUtils::get($dataInfo, 'type', ArrayUtils::get($data, 'type')); - - if (strpos($type, 'embed/') === 0) { - $recordData = $files->saveEmbedData(array_merge($dataInfo, ArrayUtils::pick($data, ['filename']))); - } else { - $recordData = $files->saveData($payload['data'], $payload['filename'], $replace); - } - - // NOTE: Use the user input title, tags, description and location when exists. - $recordData = ArrayUtils::defaults($recordData, ArrayUtils::pick($data, [ - 'title', - 'tags', - 'description', - 'location', - ])); - - $payload->replace($recordData); - $payload->remove('data'); - $payload->remove('html'); - if (!$replace) { - /** @var Acl $auth */ - $acl = $container->get('acl'); - $payload->set('uploaded_by', $acl->getUserId()); - $payload->set('uploaded_on', DateTimeUtils::now()->toString()); - } - }; - $emitter->addFilter('item.update:before', function (Payload $payload) use ($container, $savesFile) { + $emitter->addFilter('item.update:before', function (Payload $payload) use ($container) { $collection = SchemaService::getCollection($payload->attribute('collection_name')); /** @var Acl $acl */ @@ -368,22 +311,16 @@ protected function getEmitter() $payload->remove('date_uploaded'); } - $savesFile($payload, true); - return $payload; }, Emitter::P_HIGH); - $emitter->addFilter('item.create:before', function (Payload $payload) use ($savesFile) { - $savesFile($payload, false); - return $payload; - }); $addFilesUrl = function ($rows) { return \Directus\append_storage_information($rows); }; $emitter->addFilter('item.read.directus_files:before', function (Payload $payload) { $columns = $payload->get('columns'); - if (!in_array('filename', $columns)) { - $columns[] = 'filename'; + if (!in_array('filename_disk', $columns)) { + $columns[] = 'filename_disk'; $payload->set('columns', $columns); } return $payload; @@ -547,7 +484,6 @@ protected function getEmitter() $emitter->addFilter('item.read.directus_files', function (Payload $payload) use ($addFilesUrl, $container) { $rows = $addFilesUrl($payload->getData()); - $payload->replace($rows); return $payload; @@ -676,7 +612,7 @@ protected function getEmitter() $emitter->addFilter('item.create:before', $onInsertOrUpdate); $emitter->addFilter('item.update:before', $onInsertOrUpdate); - + $beforeSavingFiles = function ($payload) use ($container) { $acl = $container->get('acl'); if (!$acl->canCreate('directus_files')) { @@ -711,19 +647,23 @@ protected function getEmitter() $emitter->addAction('auth.request:credentials', function () use ($container) { /** @var Session $session */ $session = $container->get('session'); - if ($session->getStorage()->get('telemetry') === true) { - return; - } + $useTelemetry = get_directus_setting('telemetry',true); - $data = [ - 'version' => Application::DIRECTUS_VERSION, - 'url' => get_url(), - 'type' => 'api' - ]; - \Directus\request_send_json('POST', 'https://telemetry.directus.io/count', $data); + if($useTelemetry) { + if ($session->getStorage()->get('telemetry') === true) { + return; + } - // NOTE: this only works when the client sends subsequent request with the same cookie - $session->getStorage()->set('telemetry', true); + $data = [ + 'version' => Application::DIRECTUS_VERSION, + 'url' => get_url(), + 'type' => 'api' + ]; + \Directus\request_send_json('POST', 'https://telemetry.directus.io/count', $data); + + // NOTE: this only works when the client sends subsequent request with the same cookie + $session->getStorage()->set('telemetry', true); + } }); return $emitter; diff --git a/src/core/Directus/Application/Http/Middleware/ResponseCacheMiddleware.php b/src/core/Directus/Application/Http/Middleware/ResponseCacheMiddleware.php index 542173a581..f86955eaef 100644 --- a/src/core/Directus/Application/Http/Middleware/ResponseCacheMiddleware.php +++ b/src/core/Directus/Application/Http/Middleware/ResponseCacheMiddleware.php @@ -41,7 +41,7 @@ public function __invoke(Request $request, Response $response, callable $next) $requestPath = $request->getUri()->getPath(); - $key = md5($container->get('acl')->getUserId().'@'.$requestPath.'?'.http_build_query($parameters)); + $key = md5($container->get('acl')->getUserId() . '@' . $requestPath . '?' . http_build_query($parameters)); } else if ($request->isPost() && StringUtils::endsWith($request->getUri()->getPath(), '/gql')) { // Handle caching for GraphQL query that are POST. // TODO:: Add support for ACL and Mutation @@ -71,17 +71,17 @@ public function __invoke(Request $request, Response $response, callable $next) $authorizationTokenObject = get_request_authorization_token($request); $accessToken = null; - try{ - if(!empty($authorizationTokenObject['token'])){ + try { + if (!empty($authorizationTokenObject['token'])) { $userSessionService = new UserSessionService($container); $userSessionService->destroy([ 'token_expired_at < ?' => DateTimeUtils::now()->toString() ]); $expirationMinutes = get_directus_setting('auto_sign_out'); - $expiry = new \DateTimeImmutable('now + '.$expirationMinutes.'minutes'); + $expiry = new \DateTimeImmutable('now + ' . $expirationMinutes . 'minutes'); - switch($authorizationTokenObject['type']){ - case DirectusUserSessionsTableGateway::TOKEN_COOKIE : + switch ($authorizationTokenObject['type']) { + case DirectusUserSessionsTableGateway::TOKEN_COOKIE: $accessToken = decrypt_static_token($authorizationTokenObject['token']); $userSession = $userSessionService->find(['token' => $accessToken]); $cookie = new Cookies(); @@ -91,29 +91,41 @@ public function __invoke(Request $request, Response $response, callable $next) [ 'value' => $authorizationTokenObject['token'], 'expires' => $expiryAt, - 'path'=>'/', + 'path' => '/', 'httponly' => true ] ); - $response = $response->withAddedHeader('Set-Cookie',$cookie->toHeaders()); + $response = $response->withAddedHeader('Set-Cookie', $cookie->toHeaders()); break; - default : + default: $userSession = $userSessionService->find(['token' => $authorizationTokenObject['token']]); break; } } - if(isset($userSession)){ - $userSessionService->update($userSession['id'],['token_expired_at' => $expiry->format('Y-m-d H:i:s')]); + if (isset($userSession)) { + $userSessionService->update($userSession['id'], ['token_expired_at' => $expiry->format('Y-m-d H:i:s')]); } - }catch(\Exception $e){ + } catch (\Exception $e) { $container->get('logger')->error($e->getMessage()); + $cookie = new Cookies(); + $cookie->set( + get_project_session_cookie_name($request), + [ + 'value' => $authorizationTokenObject['token'], + 'expires' => DateTimeUtils::now()->toString(), + 'path' => '/', + 'httponly' => true + ] + ); + + $response = $response->withAddedHeader('Set-Cookie', $cookie->toHeaders()); } $response = $response->withHeader('Access-Control-Allow-Origin', $request->getHeader('Origin')); $config = $container->get('config'); if ($config->get('cors.credentials')) { - $response = $response->withHeader('Access-Control-Allow-Credentials', 'true'); + $response = $response->withHeader('Access-Control-Allow-Credentials', 'true'); } return $response; } diff --git a/src/core/Directus/Authentication/Exception/TFAEnforcedException.php b/src/core/Directus/Authentication/Exception/TFAEnforcedException.php index 91980f4e52..4ca9c1da0d 100644 --- a/src/core/Directus/Authentication/Exception/TFAEnforcedException.php +++ b/src/core/Directus/Authentication/Exception/TFAEnforcedException.php @@ -11,6 +11,6 @@ class TFAEnforcedException extends UnauthorizedException public function __construct() { - parent::__construct(ERROR_MESSAGE); + parent::__construct(static::ERROR_MESSAGE); } } diff --git a/src/core/Directus/Config/Schema/Schema.php b/src/core/Directus/Config/Schema/Schema.php index 3b4c27537f..692febd531 100644 --- a/src/core/Directus/Config/Schema/Schema.php +++ b/src/core/Directus/Config/Schema/Schema.php @@ -19,14 +19,9 @@ public static function get() { } return new Group('directus', [ - new Group('app', [ - new Value('env', Types::STRING, 'production'), - new Value('timezone', Types::STRING, 'America/New_York'), - ]), - new Group('settings', [ - new Group('logger', [ - new Value('path', Types::STRING, $loggerPath), - ]) + new Value('env', Types::STRING, 'production'), + new Group('logger', [ + new Value('path', Types::STRING, $loggerPath), ]), new Group('database', [ new Value('type', Types::STRING, 'mysql'), @@ -54,7 +49,7 @@ public static function get() { new Value('adapter', Types::STRING, 'local'), new Value('root', Types::STRING, 'public/uploads/_/originals'), new Value('root_url', Types::STRING, '/uploads/_/originals'), - new Value('thumb_root', Types::STRING, 'public/uploads/_/thumbnails'), + new Value('thumb_root', Types::STRING, 'public/uploads/_/generated'), new Value('proxy_downloads?', Types::BOOLEAN, false), // S3 @@ -117,10 +112,6 @@ public static function get() { new Value('actions', Types::ARRAY, []), new Value('filters', Types::ARRAY, []), ]), - new Group('feedback', [ - new Value('token', Types::STRING, 'a-kind-of-unique-token'), - new Value('login', Types::STRING, true), - ]), new Value('tableBlacklist', Types::ARRAY, []), new Group('auth', [ new Value('secret_key', Types::STRING, ''), diff --git a/src/core/Directus/Console/Modules/InstallModule.php b/src/core/Directus/Console/Modules/InstallModule.php index d1ef957bf3..0eb65521b0 100644 --- a/src/core/Directus/Console/Modules/InstallModule.php +++ b/src/core/Directus/Console/Modules/InstallModule.php @@ -9,6 +9,8 @@ use Directus\Console\Exception\CommandFailedException; use Directus\Util\ArrayUtils; use Directus\Util\Installation\InstallerUtils; +use Directus\Util\StringUtils; +use Directus\Exception\UnauthorizedException; class InstallModule extends ModuleBase { @@ -25,6 +27,7 @@ public function __construct($basePath) $this->help = [ 'config' => '' + . PHP_EOL . "\t\t-k " . 'Project key for the created project' . PHP_EOL . "\t\t-h " . 'Hostname or IP address of the MySQL DB to be used. Default: localhost' . PHP_EOL . "\t\t-n " . 'Name of the database to use for Directus. Default: directus' . PHP_EOL . "\t\t-u " . 'Username for DB connection. Default: directus' @@ -35,6 +38,7 @@ public function __construct($basePath) . PHP_EOL . "\t\t-r " . 'Directus root URI. Default: /', 'database' => '', 'install' => '' + . PHP_EOL . "\t\t-k " . 'Project key for the created project' . PHP_EOL . "\t\t-e " . 'Administrator e-mail address, used for administration login. Default: admin@directus.com' . PHP_EOL . "\t\t-p " . 'Initial administrator password. Default: directus' . PHP_EOL . "\t\t-t " . 'Name for this Directus installation. Default: Directus' @@ -44,7 +48,7 @@ public function __construct($basePath) $this->commands_help = [ 'config' => 'Configure Directus: ' . PHP_EOL . PHP_EOL . "\t\t" - . $this->__module_name . ':config -h db_host -n db_name -u db_user -p db_pass -d directus_path' . PHP_EOL, + . $this->__module_name . ':config -k my-project -h db_host -n db_name -u db_user -p db_pass -d directus_path -a super_admin_token' . PHP_EOL, 'database' => 'Populate the Database Schema: ' . PHP_EOL . PHP_EOL . "\t\t" . $this->__module_name . ':database -d directus_path' . PHP_EOL, 'install' => 'Install Initial Configurations: ' . PHP_EOL . PHP_EOL . "\t\t" @@ -59,6 +63,7 @@ public function __construct($basePath) 'f' => 'boolean', ] ]; + } public function cmdConfig($args, $extra) @@ -70,6 +75,11 @@ public function cmdConfig($args, $extra) foreach ($args as $key => $value) { switch ($key) { + case 'a': + $data['super_admin_token'] = $value; + case 'k': + $data['project'] = (string) $value; + break; case 't': $data['db_type'] = $value; break; @@ -94,9 +104,6 @@ public function cmdConfig($args, $extra) case 'c': $data['cors_enabled'] = (bool) $value; break; - case 'N': // project Name - $data['project'] = (string) $value; - break; case 's': $data['db_socket'] = $value; break; @@ -114,7 +121,35 @@ public function cmdConfig($args, $extra) throw new \Exception(sprintf('Path "%s" does not exist', $apiPath)); } + $scannedDirectory = \Directus\scan_folder($this->getBasePath().'/config'); + $projectNames = $scannedDirectory; + + $superadminFilePath = $this->getBasePath().'/config/__api.json'; + if(empty($projectNames)){ + $requiredAttributes = ['db_name', 'db_user']; + $data['super_admin_token'] = StringUtils::randomString(16,false); + }else{ + $requiredAttributes = ['db_name', 'db_user', 'super_admin_token']; + $superadminFileData = json_decode(file_get_contents($superadminFilePath), true); + if (!is_null($data['super_admin_token']) && $data['super_admin_token'] !== $superadminFileData['super_admin_token']) { + throw new UnauthorizedException('Permission denied: Superadmin Only'); + } + } + if (!ArrayUtils::contains($data, $requiredAttributes)) { + throw new \InvalidArgumentException( + 'Creating config files required: ' . implode(', ', $requiredAttributes) + ); + } + if(empty($projectNames)){ + $configStub = InstallerUtils::createJsonFileContent($data); + file_put_contents($superadminFilePath, $configStub); + } InstallerUtils::createConfig($directusPath, $data, $force); + + if(empty($projectNames)){ + echo PHP_EOL . "Make sure to copy the generated Super-Admin password below. You won't be able to see it again!". PHP_EOL; + echo PHP_EOL . $data['super_admin_token'] . PHP_EOL; + } } public function cmdDatabase($args, $extra) @@ -128,7 +163,7 @@ public function cmdDatabase($args, $extra) case 'd': $directus_path = $value; break; - case 'N': + case 'k': $projectName = $value; break; case 'f': @@ -138,6 +173,7 @@ public function cmdDatabase($args, $extra) } InstallerUtils::createTables($directus_path, $projectName, $force); + InstallerUtils::addUpgradeMigrations($this->getBasePath(),$projectName); } public function cmdSeeder($args, $extra) @@ -170,7 +206,7 @@ public function cmdInstall($args, $extra) case 'T': $data['user_token'] = $value; break; - case 'N': + case 'k': $projectName = $value; break; case 'timezone': diff --git a/src/core/Directus/Database/TableGateway/BaseTableGateway.php b/src/core/Directus/Database/TableGateway/BaseTableGateway.php index 425d0a4e8e..a8725c9cda 100644 --- a/src/core/Directus/Database/TableGateway/BaseTableGateway.php +++ b/src/core/Directus/Database/TableGateway/BaseTableGateway.php @@ -47,6 +47,7 @@ use Zend\Db\TableGateway\Feature; use Zend\Db\TableGateway\Feature\RowGatewayFeature; use Zend\Db\TableGateway\TableGateway; +use function Directus\get_random_string; class BaseTableGateway extends TableGateway { @@ -376,7 +377,7 @@ public function addRecordByArray(array $recordData) $hookName = 'item.create.' . SchemaManager::COLLECTION_FILES; // TODO: Implement once execute. Allowing a hook callback to run once. $listenerId = static::$emitter->addAction($hookName, function ($data) use (&$recordData) { - $recordData['filename'] = $data['filename']; + $recordData['filename_disk'] = $data['filename_disk']; }, Emitter::P_LOW); } @@ -388,7 +389,6 @@ public function addRecordByArray(array $recordData) } $TableGateway->insert($recordData); - if (static::$emitter && $listenerId) { static::$emitter->removeListenerWithIndex($listenerId); } @@ -399,9 +399,8 @@ public function addRecordByArray(array $recordData) $recordData[$primaryKey] = $TableGateway->getLastInsertValue(); } - $this->afterAddOrUpdate($recordData); - $columns = SchemaService::getAllNonAliasCollectionFieldNames($this->table); + return $TableGateway->fetchAll(function (Select $select) use ($recordData, $columns, $primaryKey) { $select ->columns($columns) @@ -426,26 +425,6 @@ public function updateRecordByArray(array $recordData) } $recordId = $recordData[$primaryKey]; - if ($collectionName === SchemaManager::COLLECTION_FILES) { - $select = new Select($collectionName); - $select->columns(['filename']); - $select->where([ - $primaryKey => $recordId - ]); - $select->limit(1); - $result = $TableGateway->ignoreFilters()->selectWith($select); - - if ($result->count() === 0) { - throw new ItemNotFoundException(); - } - - $currentItem = $result->current()->toArray(); - - $originalFilename = ArrayUtils::get($currentItem, 'filename'); - $recordData = array_merge([ - 'filename' => $originalFilename - ], $recordData); - } $Update = new Update($collectionName); $Update->set($recordData); @@ -454,20 +433,6 @@ public function updateRecordByArray(array $recordData) ]); $TableGateway->updateWith($Update); - $replace = true; - if ($collectionName === SchemaManager::COLLECTION_FILES && static::$container) { - $changeFilename = $originalFilename && $recordData['filename'] !== $originalFilename; - $replace = !$changeFilename; - - if ($changeFilename) { - /** @var Files $Files */ - $Files = static::$container->get('files'); - $Files->delete(['filename' => $originalFilename]); - } - } - - $this->afterAddOrUpdate($recordData, $replace); - $columns = SchemaService::getAllNonAliasCollectionFieldNames($collectionName); return $TableGateway->fetchAll(function ($select) use ($recordData, $columns, $primaryKey) { $select @@ -727,7 +692,6 @@ protected function executeSelect(Select $select) $selectState = $select->getRawState(); $selectCollectionName = $selectState['table']; - if ($useFilter) { $selectState = $this->applyHooks([ 'item.read:before', @@ -912,7 +876,7 @@ protected function executeDelete(Delete $delete) $deleteState = $delete->getRawState(); $deleteTable = $this->getRawTableNameFromQueryStateTable($deleteState['table']); - + // Runs select PK with passed delete's $where before deleting, to use those for the even hook if ($pk = $this->primaryKeyFieldName) { $select = $this->sql->select(); @@ -931,7 +895,7 @@ protected function executeDelete(Delete $delete) $delete = $this->sql->delete(); $expression = new In($pk, $ids); $delete->where($expression); - + foreach ($ids as $id) { $deleteData = [$this->primaryKeyFieldName => $id]; $this->runHook('item.delete:before', [$deleteTable, $deleteData]); @@ -947,7 +911,7 @@ protected function executeDelete(Delete $delete) ); } - + //Invalidate individual cache if (static::$container) { $config = static::$container->get('config'); @@ -1809,55 +1773,6 @@ protected function validateRecordArray(array $record) } } - /** - * @param array $record - * @param bool $replace - */ - protected function afterAddOrUpdate(array $record, $replace = false) - { - // TODO: Move this to a proper hook - $hasData = ArrayUtils::has($record, 'data') && is_string($record['data']); - $isFilesCollection = $this->table == SchemaManager::COLLECTION_FILES; - - if (!static::$container || !$hasData || !$isFilesCollection) { - return; - } - - $Files = static::$container->get('files'); - - $updateArray = []; - if ($Files->getSettings('file_naming') == 'id') { - $ext = $thumbnailExt = pathinfo($record['filename'], PATHINFO_EXTENSION); - $fileId = $record[$this->primaryKeyFieldName]; - // TODO: The left padding should be based on the max length of the primary - $newFilename = filename_put_ext(str_pad( - $fileId, - 11, - '0', - STR_PAD_LEFT - ), $ext); - - // overwrite a file with this file content if it already exists - if (!$replace) { - $Files->rename( - $record['filename'], - $newFilename, - true - ); - } - - $updateArray['filename'] = $newFilename; - $record['filename'] = $updateArray['filename']; - } - - if (!empty($updateArray)) { - $Update = new Update($this->table); - $Update->set($updateArray); - $Update->where([$this->primaryKeyFieldName => $record[$this->primaryKeyFieldName]]); - $this->updateWith($Update); - } - } - /** * Checks whether or not null should be sorted last * diff --git a/src/core/Directus/Database/TableGateway/RelationalTableGateway.php b/src/core/Directus/Database/TableGateway/RelationalTableGateway.php index 9ea1a0b6d5..0804a3ecbf 100644 --- a/src/core/Directus/Database/TableGateway/RelationalTableGateway.php +++ b/src/core/Directus/Database/TableGateway/RelationalTableGateway.php @@ -721,9 +721,9 @@ public function addOrUpdateToManyRelationships($schema, $parentRow, &$childLogEn if(strtolower($column->getType()) == DataTypes::TYPE_USER_CREATED || strtolower($column->getType()) == DataTypes::TYPE_USER_UPDATED){ unset($foreignRecord[$column->getName()]); } - } + } } - + $foreignRecord = $ForeignTable->manageRecordUpdate( $foreignTableName, $foreignRecord, @@ -793,7 +793,7 @@ public function applyDefaultEntriesSelectParams(array $params) if (!isset($params['offset']) && isset($params['page']) && isset($params['limit'])) { $params['offset'] = $params['limit'] * ($params['page'] - 1); } - + $params = array_merge($defaultParams, $params); if (ArrayUtils::get($params, 'sort')) { @@ -1017,7 +1017,7 @@ public function createEntriesMetadata(array $entries, array $list = []) $condition = new In($fieldName, $this->getNonSoftDeleteStatuses()); } $countedData['total_count'] = $this->countTotal($condition); - + if (in_array('total_count', $list)) { $metadata['total_count'] = $this->countTotal($condition); } @@ -1060,7 +1060,7 @@ public function createMetadataPagination(array $metadata = [], array $params = [ $meta_param=explode(',',$params['meta']); if((in_array('filter_count',$meta_param) || in_array('*',$meta_param))) { $metadata['filter_count'] = $countedData['total_count']; - } + } if ($filtered) { $filteredparams = array_merge($params, [ @@ -1075,7 +1075,7 @@ public function createMetadataPagination(array $metadata = [], array $params = [ $metadata['filter_count'] = $total; } } - + $limit = $limit < 1 ? $rows : $limit; $pages = $total ? ceil($total / $limit) : 1; $page = $page > $pages ? $pages : ($page && $offset >= 0 ? (floor($offset / $limit) + 1) : $page); @@ -1089,7 +1089,7 @@ public function createMetadataPagination(array $metadata = [], array $params = [ $last = ($pages < 2) ? null : (($pages - 1) * $limit); } - + if(in_array('page',$meta_param) || in_array('*',$meta_param)) { $metadata = array_merge($metadata, [ "limit" => $limit, @@ -1127,7 +1127,7 @@ public function fetchItems(array $params = [], \Closure $queryCallback = null) $params = $this->applyDefaultEntriesSelectParams($params); $fields = ArrayUtils::get($params, 'fields'); - + // TODO: Check for all collections + fields permission/existence before querying // TODO: Create a new TableGateway Query Builder based on Query\Builder @@ -1135,7 +1135,7 @@ public function fetchItems(array $params = [], \Closure $queryCallback = null) $builder->from($this->getTable()); $selectedFields = $this->getSelectedNonAliasFields($fields ?: ['*']); - + if (!in_array($collectionObject->getPrimaryKeyName(), $selectedFields)) { array_unshift($selectedFields, $collectionObject->getPrimaryKeyName()); } @@ -1145,10 +1145,17 @@ public function fetchItems(array $params = [], \Closure $queryCallback = null) array_unshift($selectedFields, $statusField->getName()); } - // NOTE: Make sure to have the `type` field for files to determine if the supports thumbnails - if ($this->table == SchemaManager::COLLECTION_FILES && !in_array('type', $selectedFields)) { + if ($this->table == SchemaManager::COLLECTION_FILES) { + // NOTE: Make sure to have the `type` field for files to determine if the supports thumbnails + if(!in_array('type', $selectedFields)) { $selectedFields[] = 'type'; + } + // NOTE: Make sure to have the `private_hash` field for files to display in URLs + if (!in_array('private_hash', $selectedFields)) { + $selectedFields[] = 'private_hash'; + } } + $builder->columns($selectedFields); $builder = $this->applyParamsToTableEntriesSelect( @@ -1221,11 +1228,15 @@ public function fetchItems(array $params = [], \Closure $queryCallback = null) 'lang' => ArrayUtils::get($params, 'lang') ]; - $results = $this->loadRelationalData( + $resultArray = $this->loadRelationalData( $results, \Directus\get_array_flat_columns($relatedFields), $relationalParams ); + + if(!empty($resultArray)){ + $results = $resultArray; + } } // When the params column list doesn't include the primary key @@ -1332,7 +1343,7 @@ protected function parseCondition($condition) 'logical' => $logical ]; } - + protected function parseDotFilters(Builder $mainQuery, array $filters) { foreach ($filters as $column => $condition) { @@ -1637,7 +1648,7 @@ protected function shouldIgnoreQueryFilter($operator, $value) return in_array($operator, $operators) && empty($value) && !is_numeric($value); } - + /** * Process single relation field filter * @@ -1645,7 +1656,7 @@ protected function shouldIgnoreQueryFilter($operator, $value) * @param string $column * @param array | string $condition * - * @return + * @return */ protected function processRelationalFilter(Builder $mainQuery, $column, $condition){ $columnList = $filterColumns = explode('.', $column); @@ -1786,7 +1797,7 @@ protected function processRelationalFilter(Builder $mainQuery, $column, $conditi $mainTable ); } - + /** * Process Select Filters (Where conditions) * @@ -1806,7 +1817,7 @@ protected function processFilter(Builder $query, array $filters = []) } else if (isset($fieldReadBlackListDetails['statuses']) && !empty($fieldReadBlackListDetails['statuses'])) { $blackListStatuses = array_merge($blackListStatuses, array_values($fieldReadBlackListDetails['statuses'])); } - + if (!(!is_string($column) || strpos($column, '.') === false)){ //Process relational & non relation field filters sequentially //Earlier, all the relation field filters were processing first and then non relation fields, due to that logical operators were not working in mix filters @@ -1898,13 +1909,13 @@ protected function processQ(Builder $query, $search) $relatedTable = $relationship->getCollectionMany(); $relatedRightColumn = $relationship->getFieldMany(); $relatedTableColumns = SchemaService::getAllCollectionFields($relatedTable); - + //Condition for table related to same table with O2M, to avoid right join of same tables if($relatedTable == $table){ $relatedQuery = new Builder($this->getAdapter()); $relatedQuery->columns([$relatedRightColumn]); $relatedQuery->from($relatedTable); - + foreach ($relatedTableColumns as $relatedColumn) { // NOTE: Only search numeric or string type columns $isNumeric = $this->getSchemaManager()->isFieldNumericType($relatedColumn); @@ -2335,7 +2346,7 @@ public function getSelectedFields(array $fields) public function getSelectedNonAliasFields(array $fields) { $nonAliasFields = SchemaService::getAllNonAliasCollectionFieldsName($this->getTableSchema()->getName()); - + $allFields = $this->replaceWildcardFieldWith( $fields, $nonAliasFields diff --git a/src/core/Directus/Filesystem/Files.php b/src/core/Directus/Filesystem/Files.php index 35ca45cba8..2440cc60a4 100644 --- a/src/core/Directus/Filesystem/Files.php +++ b/src/core/Directus/Filesystem/Files.php @@ -265,11 +265,14 @@ public function getDataInfo($data) /** * Copy base64 data into Directus Media * - * @param string $fileData - base64 data + * @param string $fileData - base64 data or directus_files object * @param string $fileName - name of the file * @param bool $replace * * @return array + * + * @todo Refactor this to be clearer what's going on. $fileData can be anything, + * all kinds of things are happening, and nothing is documented */ public function saveData($fileData, $fileName, $replace = false) { @@ -289,12 +292,17 @@ public function saveData($fileData, $fileName, $replace = false) } // @TODO: merge with upload() $fileName = $this->getFileName($fileName, $replace !== true); - $filePath = $this->getConfig('root') . '/' . $fileName; - + $ext = pathinfo($fileName, PATHINFO_EXTENSION); $event = $replace ? 'file.update' : 'file.save'; $this->emitter->run($event, ['name' => $fileName, 'size' => $size]); - $this->write($fileName, $fileData, $replace); + + // On name change, the file would be overwritten with the empty file data. + // This prevents you can't update a file to a zero-byte file. + if (!empty($fileData)) { + $this->write($fileName, $fileData, $replace); + } + $this->emitter->run($event.':after', ['name' => $fileName, 'size' => $size]); #open local tmp file since s3 bucket is private @@ -308,7 +316,7 @@ public function saveData($fileData, $fileName, $replace = false) $fileData = $this->getFileInfo($fileName); $fileData['title'] = Formatting::fileNameToFileTitle($title); - $fileData['filename'] = basename($filePath); + $fileData['filename_disk'] = basename($filePath); $fileData['storage'] = $this->config['adapter']; $fileData = array_merge($this->defaults, $fileData); @@ -333,11 +341,10 @@ public function saveData($fileData, $fileName, $replace = false) } unset($tmpData); - return [ - // The MIME type will be based on its extension, rather than its content - 'type' => MimeTypeUtils::getFromFilename($fileData['filename']), - 'filename' => $fileData['filename'], - 'title' => $fileData['title'], + $response = [ + // The MIME type will be based on its extension, rather than its extension + 'type' => MimeTypeUtils::getFromFilename($fileData['filename_disk']), + 'filename_disk' => $fileData['filename_disk'], 'tags' => $fileData['tags'], 'description' => $fileData['description'], 'location' => $fileData['location'], @@ -349,6 +356,12 @@ public function saveData($fileData, $fileName, $replace = false) 'checksum' => $checksum, 'duration' => isset($duration) ? $duration : 0 ]; + + if(!$replace){ + $response['title'] = $fileData['title']; + } + + return $response; } /** @@ -365,7 +378,7 @@ public function saveEmbedData(array $fileInfo) } $fileName = isset($fileInfo['filename']) ? $fileInfo['filename'] : md5(time()) . '.jpg'; - $thumbnailData = $this->saveData($fileInfo['data'], $fileName); + $thumbnailData = $this->saveData($fileInfo['data'], $fileName,$fileInfo['fileId']); return array_merge( $fileInfo, @@ -675,16 +688,14 @@ public function uniqueName($fileName, $targetPath = null, $attempt = 0) */ private function getFileName($fileName, $unique = true) { - switch ($this->getSettings('file_naming')) { - case 'uuid': - $fileName = $this->uuidFileName($fileName); - break; - } - if ($unique) { + switch ($this->getSettings('file_naming')) { + case 'uuid': + $fileName = $this->uuidFileName($fileName); + break; + } $fileName = $this->uniqueName($fileName, $this->filesystem->getPath()); } - return $fileName; } diff --git a/src/core/Directus/Filesystem/Thumbnailer.php b/src/core/Directus/Filesystem/Thumbnailer.php index e30f187429..fe5c89f90b 100644 --- a/src/core/Directus/Filesystem/Thumbnailer.php +++ b/src/core/Directus/Filesystem/Thumbnailer.php @@ -59,30 +59,27 @@ public function __construct(Filesystem $main, Filesystem $thumb, array $config, $this->config = $config; $this->params = $params; - $this->thumbnailParams = $this->extractThumbnailParams($path); + $this->thumbnailParams = $this->validateThumbnailParams($path,$params); - // check if the original file exists in storage + // // check if the original file exists in storage if (! $this->filesystem->exists($this->fileName)) { throw new Exception($this->fileName . ' does not exist.'); // original file doesn't exist } - // check if dimensions are supported - if (! $this->isSupportedThumbnailDimension($this->width, $this->height)) { - throw new Exception('Invalid dimensions.'); - } + $this->validateThumbnailWhitelist($params); - // check if action is supported - if ( $this->action && ! $this->isSupportedAction($this->action)) { - throw new Exception('Invalid action.'); - } + $otherParams=$params; + unset($otherParams['width'],$otherParams['height'],$otherParams['fit'],$otherParams['quality']); - // check if quality is supported - if ( $this->quality && ! $this->isSupportedQualityTag($this->quality)) { - throw new Exception('Invalid quality.'); + if(count($otherParams) > 0) { + ksort($otherParams); + $paramsString=''; + foreach($otherParams as $key => $value) { + $paramsString .= ','. substr($key, 0, 1) . $value; + } } - // relative to configuration['storage']['thumb_root'] - $this->thumbnailDir = $this->width . '/' . $this->height . ($this->action ? '/' . $this->action : '') . ($this->quality ? '/' . $this->quality : ''); + $this->thumbnailDir = 'w'.$params['width'] . ',h' . $params['height'] . ',f' . $params['fit'] . ',q' . $params['quality'].$paramsString; } catch (Exception $e) { throw $e; } @@ -171,7 +168,7 @@ public function contain() { try { // action options - $options = $this->getSupportedActionOptions($this->action); + $options = $this->getSupportedActionOptions($this->$params); // open file image resource $img = $this->load(); @@ -188,7 +185,7 @@ public function contain() $img->resizeCanvas($this->width, $this->height, ArrayUtils::get($options, 'position', 'center'), ArrayUtils::get($options, 'resizeRelative', false), ArrayUtils::get($options, 'canvasBackground', [255, 255, 255, 0])); } - $encodedImg = (string) $img->encode($this->format, ($this->quality ? $this->translateQuality($this->quality) : null)); + $encodedImg = (string) $img->encode($this->format, ($this->quality ? $this->quality : null)); $this->filesystemThumb->write($this->thumbnailDir . '/' . $this->thumbnailFileName, $encodedImg); return $encodedImg; @@ -220,7 +217,7 @@ public function crop() // resize/crop image $img->fit($this->width, $this->height, function($constraint){}, ArrayUtils::get($options, 'position', 'center')); - $encodedImg = (string) $img->encode($this->format, ($this->quality ? $this->translateQuality($this->quality) : null)); + $encodedImg = (string) $img->encode($this->format, ($this->quality ? $this->quality : null)); $this->filesystemThumb->write($this->thumbnailDir . '/' . $this->thumbnailFileName, $encodedImg); return $encodedImg; @@ -232,13 +229,14 @@ public function crop() } /** - * Parse url and extract thumbnail params + * validate params and file extensions and return it * * @param string $thumbnailUrlPath + * @param array $params * @throws Exception * @return array */ - public function extractThumbnailParams($thumbnailUrlPath) + public function validateThumbnailParams($thumbnailUrlPath,$params) { // cache if ($this->thumbnailParams) { @@ -248,31 +246,37 @@ public function extractThumbnailParams($thumbnailUrlPath) // get URL parts // https://docs.directus.io/guides/thumbnailer.html#url-syntax $urlSegments = explode('/', $thumbnailUrlPath); - if (count($urlSegments) < 6) { - throw new Exception('Invalid URL syntax.'); - } // pull the env out of the segments array_shift($urlSegments); // set thumbnail parameters $thumbnailParams = [ - 'action' => filter_var($urlSegments[2], FILTER_SANITIZE_STRING), - 'height' => filter_var($urlSegments[1], FILTER_SANITIZE_NUMBER_INT), - 'quality' => filter_var($urlSegments[3], FILTER_SANITIZE_STRING), - 'width' => filter_var($urlSegments[0], FILTER_SANITIZE_NUMBER_INT), + 'fit' => filter_var($params['fit'], FILTER_SANITIZE_STRING), + 'height' => filter_var($params['height'], FILTER_SANITIZE_NUMBER_INT), + 'quality' => filter_var($params['quality'], FILTER_SANITIZE_STRING), + 'width' => filter_var($params['width'], FILTER_SANITIZE_NUMBER_INT), ]; - // validate parameters - if (! ArrayUtils::contains($thumbnailParams, [ - 'width', - 'height' - ])) { - throw new Exception('No height or width provided.'); + if($thumbnailParams['width'] == null || $thumbnailParams['width'] == '') + { + throw new Exception('No width is provided.'); + } + if($thumbnailParams['height'] == null || $thumbnailParams['height'] == '') + { + throw new Exception('No height is provided.'); + } + if($thumbnailParams['fit'] == null || $thumbnailParams['fit'] == '') + { + throw new Exception('No fit is provided.'); + } + if($thumbnailParams['quality'] == null || $thumbnailParams['quality'] == '') + { + throw new Exception('No quality is provided.'); } // make sure filename is valid - $filename = implode('/', array_slice($urlSegments, 4)); + $filename = $urlSegments[1]; $ext = pathinfo($filename, PATHINFO_EXTENSION); $name = pathinfo($filename, PATHINFO_FILENAME); if (! $this->isSupportedFileExtension($ext)) { @@ -305,6 +309,44 @@ public function extractThumbnailParams($thumbnailUrlPath) return $thumbnailParams; } + /** + * validate params against thumbnail whitelist + * + * @param array $params + * @throws Exception + * @return boolean + */ + + public function validateThumbnailWhitelist($params) + { + $userWhitelist = json_decode(ArrayUtils::get($this->getConfig(), 'asset_whitelist'), true); + + $thumbnailWhitelistEnabled = empty($userWhitelist) === false; + + if($thumbnailWhitelistEnabled) + { + $userWhitelist = json_decode($userWhitelist,true); + $result = false; + foreach($userWhitelist as $key=>$value) + { + if( + $value['width'] == $params['width'] && + $value['height'] == $params['height'] && + $value['fit'] == $params['fit'] && + $value['quality'] == $params['quality'] + ) + { + $result = true; + } + } + if(!$result){ + throw new Exception(); + } + } + + } + + /** * Translate quality text to number and return * diff --git a/src/core/Directus/GraphQL/FieldsConfig.php b/src/core/Directus/GraphQL/FieldsConfig.php index 524654c573..9353c435f0 100644 --- a/src/core/Directus/GraphQL/FieldsConfig.php +++ b/src/core/Directus/GraphQL/FieldsConfig.php @@ -50,7 +50,10 @@ public function getFields() $fields[$v['field']] = Types::directusFile(); break; case 'integer': - $fields[$v['field']] = ($v['interface'] == 'primary-key') ? $fields[$v['field']] = Types::id() : Types::int(); + $fields[$v['field']] = Types::int(); + if ($v['primary_key']) { + $fields[$v['field']] = Types::id(); + } break; case 'decimal': $fields[$v['field']] = Types::float(); diff --git a/src/core/Directus/Services/AbstractService.php b/src/core/Directus/Services/AbstractService.php index 213d3f1d7b..4da5f078d8 100644 --- a/src/core/Directus/Services/AbstractService.php +++ b/src/core/Directus/Services/AbstractService.php @@ -193,7 +193,7 @@ protected function throwErrorIfAny(array $violations,$errorCode = "") * @param string $collectionName * @param array $fields List of columns name * @param array $skipRelatedCollectionField To skip parent collection field validation - * + * * @return array */ protected function createConstraintFor($collectionName, array $fields = [], $skipRelatedCollectionField = '', array $params = [] ) @@ -209,17 +209,17 @@ protected function createConstraintFor($collectionName, array $fields = [], $ski } foreach ($collectionObject->getFields($fields) as $field) { - //This condition is placed to skip alias validation field which is related to parent collection, + //This condition is placed to skip alias validation field which is related to parent collection, //to avoid nested payload validation for O2M and M2O collections - if($field->hasRelationship() && !empty($skipRelatedCollectionField) && (($field->getRelationship()->isManyToOne() && $field->getRelationship()->getCollectionOne() == $skipRelatedCollectionField) || ($field->getRelationship()->isOneToMany() && $field->getRelationship()->getCollectionMany() == $skipRelatedCollectionField))) + if($field->hasRelationship() && !empty($skipRelatedCollectionField) && (($field->getRelationship()->isManyToOne() && $field->getRelationship()->getCollectionOne() == $skipRelatedCollectionField) || ($field->getRelationship()->isOneToMany() && $field->getRelationship()->getCollectionMany() == $skipRelatedCollectionField))) continue; - + $columnConstraints = []; if ($field->hasAutoIncrement()) { continue; } - + if($field->isSystemDateTimeType() || $field->isSystemUserType()){ continue; } @@ -232,9 +232,12 @@ protected function createConstraintFor($collectionName, array $fields = [], $ski $isStatusField = $field->isStatusType(); if (!$isRequired && $isStatusField && $field->getDefaultValue() === null) { $isRequired = true; + } else if ($isRequired === true && $field->getDefaultValue() !== null) { + $isRequired = false; } - if ($isRequired || (!$field->isNullable() && $field->getDefaultValue() == null)) { + if ($isRequired || (!$field->isNullable() && $field->getDefaultValue() == null)) + { $columnConstraints[] = 'required'; } else if (in_array($field->getName(), $fields) && !$field->isNullable()) { $columnConstraints[] = 'notnullable'; @@ -370,13 +373,13 @@ protected function getCRUDParams(array $params) * @param array $payload * @param array $params * @param array $skipRelatedCollectionField To skip parent collection field validation - * + * * @throws UnprocessableEntityException */ protected function validatePayload($collectionName, $fields, array $payload, array $params, $skipRelatedCollectionField = '') { $columnsToValidate = []; - + // TODO: Validate empty request // If the user PATCH, POST or PUT with empty body, must throw an exception to avoid continue the execution // with the exception of POST, that can use the default value instead @@ -384,13 +387,13 @@ protected function validatePayload($collectionName, $fields, array $payload, arr if (is_array($fields)) { $columnsToValidate = $fields; } - + if($this->validationRequired($collectionName,$payload)){ $this->validatePayloadFields($collectionName, $payload); // TODO: Ideally this should be part of the validator constraints // we need to accept options for the constraint builder $this->validatePayloadWithFieldsValidation($collectionName, $payload); - + $this->validate($payload, $this->createConstraintFor($collectionName, $columnsToValidate, $skipRelatedCollectionField,$params)); } @@ -485,7 +488,7 @@ protected function validatePayloadWithFieldsValidation($collectionName, array $p } $this->validateFieldLength($field, $value); - + if ($validation = $field->getValidation()) { $isCustomValidation = \Directus\is_custom_validation($validation); @@ -512,10 +515,10 @@ protected function validatePayloadWithFieldsValidation($collectionName, array $p /** * To validate the length of input with the DB. - * + * * @param array $field * @param string $value - * + * * @throws UnprocessableEntityException */ protected function validateFieldLength($field, $value) diff --git a/src/core/Directus/Services/AssetService.php b/src/core/Directus/Services/AssetService.php new file mode 100644 index 0000000000..dab61d0e17 --- /dev/null +++ b/src/core/Directus/Services/AssetService.php @@ -0,0 +1,434 @@ +collection = SchemaManager::COLLECTION_FILES; + $this->filesystem =$this->container->get('filesystem'); + $this->filesystemThumb =$this->container->get('filesystem_thumb'); + $this->config = get_directus_thumbnail_settings(); + $this->thumbnailParams = []; + } + + public function getAsset($fileHashId, array $params = []) + { + $tableGateway = $this->createTableGateway($this->collection); + $select = new Select($this->collection); + $select->columns(['filename_disk', 'filename_download', 'id', 'type']); + $select->where(['private_hash' => $fileHashId]); + $select->limit(1); + $result = $tableGateway->ignoreFilters()->selectWith($select); + + if ($result->count() == 0) { + throw new ItemNotFoundException(); + } + + $file = $result->current()->toArray(); + + // Get original image + if (count($params) == 0) { + $lastModified = $this->filesystem->getAdapter()->getTimestamp($file['filename_disk']); + $lastModified = new DateTimeUtils(date('c', $lastModified)); + + $img = $this->filesystem->read($file['filename_disk']); + $result = []; + $result['last_modified'] = $lastModified->toRFC2616Format(); + $result['mimeType'] = $file['type']; + $result['file'] = isset($img) && $img ? $img : null; + $result['filename'] = $file['filename_disk']; + $result['filename_download'] = $file['filename_download']; + + return $result; + }else{ + + $this->fileName = $file['filename_disk']; + $this->fileNameDownload = $file['filename_download']; + try { + return $this->getThumbnail($params); + } + catch(Exception $e) + { + throw new UnprocessableEntityException(sprintf($e->getMessage())); + } + } + } + + public function getThumbnail($params) + { + $this->thumbnailParams=$params; + + $this->validateThumbnailParams($params); + + if (! $this->filesystem->exists($this->fileName)) { + throw new Exception($this->fileName . ' does not exist.'); + } + + $this->thumbnailDir = 'w' . $this->thumbnailParams['width'] . ',h' . $this->thumbnailParams['height'] . + ',f' . $this->thumbnailParams['fit'] . ',q' . $this->thumbnailParams['quality']; + + try { + $image = $this->getExistingThumbnail(); + + if (!$image) { + switch ($this->thumbnailParams['fit']) { + case 'contain': + $image = $this->contain(); + break; + case 'crop': + default: + $image = $this->crop(); + } + } + + $result['mimeType'] = $this->getThumbnailMimeType($this->thumbnailDir, $this->fileName); + $result['last_modified'] = $this->getThumbnailLastModified($this->thumbnailDir, $this->fileName); + $result['file'] = $image; + $result['filename_download'] = $this->fileNameDownload; + return $result; + } + catch (Exception $e) { + throw $e; + } + } + + /** + * validate params and file extensions and return it + * + * @param string $thumbnailUrlPath + * @param array $params + * @throws Exception + * @return array + */ + public function validateThumbnailParams($params) + { + // If the user provided the key param + $usesKey = isset($params['key']); + + // The user provided whitelist. If this is empty, any combination of the params is allowed + $userWhitelist = json_decode(ArrayUtils::get($this->getConfig(), 'asset_whitelist'), true); + + // The system native thumbnails that can't be changed + $systemWhitelist = json_decode(ArrayUtils::get($this->getConfig(), 'asset_whitelist_system'), true); + + // If the whitelist is set and therefore mandatory + $whitelistEnabled = empty($userWhitelist) == false; + + // All available sizes in the system + $allSizes = $whitelistEnabled ? array_merge($systemWhitelist, $userWhitelist) : $systemWhitelist; + + if ($usesKey) { + // Retrieve the sizes by the key that's passed + $exists = false; + + foreach($allSizes as $key => $value) { + if ($value['key'] == $params['key']) { + $exists = true; + $params = [ + 'w'=> $value['width'], + 'h' => $value['height'], + 'q' => $value['quality'], + 'f' => $value['fit'], + 'key' => $params['key'] + ]; + } + } + + if ($exists == false) { + throw new Exception(sprintf("Key doesn't exist.")); + } + + $this->thumbnailParams['key']= filter_var($params['key'], FILTER_SANITIZE_STRING); + } + + // We require all the params to be there when the key param isn't used + if ($usesKey == false) { + $this->validate( + [ + 'w' => isset($params['w']) ? $params['w'] : '', + 'h' => isset($params['h']) ? $params['h'] : '', + 'q' => isset($params['q']) ? $params['q'] : '', + 'f' => isset($params['f']) ? $params['f'] : '' + ], + [ + 'w' => 'required|numeric', + 'h' => 'required|numeric', + 'q' => 'required|numeric', + 'f' => 'required' + ] + ); + } + + // If the user didn't provide a key, and the whitelist items are required, + // verify if the passed keys match one of the predefined items + + if (!$usesKey && $whitelistEnabled) { + $exists = false; + + foreach($allSizes as $key => $value) { + if ( + $value['width'] == $params['w'] && + $value['height'] == $params['h'] && + $value['fit'] == $params['f'] && + $value['quality'] == $params['q'] + ) { + $exists = true; + } + } + + if (!$exists) { + throw new Exception(sprintf("The params don't match the asset whitelist.")); + } + } + + $this->thumbnailParams['fit']= filter_var($params['f'], FILTER_SANITIZE_STRING); + $this->thumbnailParams['height']= filter_var($params['h'], FILTER_SANITIZE_STRING); + $this->thumbnailParams['quality']= filter_var($params['q'], FILTER_SANITIZE_STRING); + $this->thumbnailParams['width']= filter_var($params['w'], FILTER_SANITIZE_STRING); + + $ext = pathinfo($this->fileName, PATHINFO_EXTENSION); + $name = pathinfo($this->fileName, PATHINFO_FILENAME); + + if (!$this->isSupportedFileExtension($ext)) { + throw new Exception('Invalid file extension.'); + } + + $this->thumbnailParams['format'] = strtolower(ArrayUtils::get($params, 'format') ?: $ext); + + if (!$this->isSupportedFileExtension($this->thumbnailParams['format'])) { + throw new Exception('Invalid file format.'); + } + + if ( + $this->thumbnailParams['format'] !== NULL && + strtolower($ext) !== $this->thumbnailParams['format'] && + !( + ($this->thumbnailParams['format'] == 'jpeg' || $this->thumbnailParams['format'] == 'jpg') && + (strtolower($ext) == 'jpeg' || strtolower($ext) == 'jpg') + ) + ) { + $this->thumbnailParams['thumbnailFileName'] = $name . '.' .$this->thumbnailParams['format']; + } else { + $this->thumbnailParams['thumbnailFileName'] = $this->fileName; + } + } + + /** + * Check if given file extension is supported + * + * @param int $ext + * @return boolean + */ + public function isSupportedFileExtension($ext) + { + return in_array(strtolower($ext), $this->getSupportedFileExtensions()); + } + + /** + * Return supported image file types + * + * @return array + */ + public function getSupportedFileExtensions() + { + return Thumbnail::getFormatsSupported(); + } + + /** + * Merge file and thumbnailer config settings and return + * + * @throws Exception + * @return array + */ + public function getConfig() + { + return $this->config; + } + + /** + * Return thumbnail as data + * + * @throws Exception + * @return string|null + */ + public function getExistingThumbnail() + { + try { + if( $this->filesystemThumb->exists($this->thumbnailDir . '/' . $this->thumbnailParams['thumbnailFileName']) ) { + $img = $this->filesystemThumb->read($this->thumbnailDir . '/' . $this->thumbnailParams['thumbnailFileName']); + } + return isset($img) && $img ? $img : null; + } + catch (Exception $e) { + throw $e; + } + } + + /** + * Replace PDF files with a JPG thumbnail + * @throws Exception + * @return string image content + */ + public function load () { + $content = $this->filesystem->read($this->fileName); + $ext = pathinfo($this->fileName, PATHINFO_EXTENSION); + if (Thumbnail::isNonImageFormatSupported($ext)) { + $content = Thumbnail::createImageFromNonImage($content); + } + return Image::make($content); + } + + /** + * Create thumbnail from image and `contain` + * http://image.intervention.io/api/resize + * https://css-tricks.com/almanac/properties/o/object-fit/ + * + * @throws Exception + * @return string + */ + public function contain() + { + try { + $img = $this->load(); + $img->resize($this->thumbnailParams['width'], $this->thumbnailParams['height'], function ($constraint) { + $constraint->aspectRatio(); + }); + $encodedImg = (string) $img->encode($this->thumbnailParams['format'], ($this->thumbnailParams['quality'] ? $this->thumbnailParams['quality'] : null)); + $this->filesystemThumb->write($this->thumbnailDir . '/' . $this->thumbnailParams['thumbnailFileName'], $encodedImg); + + return $encodedImg; + } + catch (Exception $e) { + throw $e; + } + } + + /** + * Create thumbnail from image and `crop` + * http://image.intervention.io/api/fit + * https://css-tricks.com/almanac/properties/o/object-fit/ + * + * @throws Exception + * @return string + */ + public function crop() + { + try { + $img = $this->load(); + $img->fit($this->thumbnailParams['width'],$this->thumbnailParams['height'], function($constraint){}); + $encodedImg = (string) $img->encode($this->thumbnailParams['format'], ($this->thumbnailParams['quality'] ? $this->thumbnailParams['quality'] : null)); + $this->filesystemThumb->write($this->thumbnailDir . '/' . $this->thumbnailParams['thumbnailFileName'], $encodedImg); + + return $encodedImg; + } + catch (Exception $e) { + throw $e; + } + } + + public function getDefaultThumbnail() + { + $basePath=$this->container->get('path_base'); + $filePath = ArrayUtils::get($this->config, 'thumbnail_not_found_location'); + if (is_string($filePath) && !empty($filePath) && $filePath[0] !== '/') { + $filePath = $basePath . '/' . $filePath; + } + + if (file_exists($filePath)) { + $result['mimeType'] = image_type_to_mime_type(exif_imagetype($filePath)); + $result['file']=file_get_contents($filePath); + $filename = pathinfo($filePath); + $result['filename']= $filename['basename']; + return $result; + } else { + return http_response_code(404); + } + } + + public function getThumbnailMimeType($path, $fileName) + { + try { + if($this->filesystemThumb->exists($path . '/' . $fileName) ) { + if(strtolower(pathinfo($fileName, PATHINFO_EXTENSION)) == 'webp') { + return 'image/webp'; + } + $img = Image::make($this->filesystemThumb->read($path. '/' . $fileName)); + return $img->mime(); + } + return 'application/octet-stream'; + } + + catch (Exception $e) { + throw $e; + } + } + + public function getThumbnailLastModified($path, $fileName) + { + try { + $lastModified = $this->filesystemThumb->getAdapter()->getTimestamp($path . '/' . $fileName); + $lastModified = new DateTimeUtils(date('c', $lastModified)); + return $lastModified->toRFC2616Format(); + } + + catch (Exception $e) { + throw $e; + } + } +} diff --git a/src/core/Directus/Services/FilesServices.php b/src/core/Directus/Services/FilesServices.php index ef0ffaff4a..2f17049484 100644 --- a/src/core/Directus/Services/FilesServices.php +++ b/src/core/Directus/Services/FilesServices.php @@ -11,8 +11,9 @@ use function Directus\get_directus_setting; use Directus\Util\ArrayUtils; use Directus\Util\DateTimeUtils; -use Directus\Filesystem\Files; use Directus\Validator\Exception\InvalidRequestException; +use function Directus\get_random_string; +use Directus\Application\Application; class FilesServices extends AbstractService { @@ -32,20 +33,19 @@ public function create(array $data, array $params = []) $this->enforceCreatePermissions($this->collection, $data, $params); $tableGateway = $this->createTableGateway($this->collection); - // These values are going to be set in a hook - // These fields should be ignore on validation as these values are automatically filled - // These values are set here to avoid validation - // FIXME: These values shouldn't not be validated $data['uploaded_by'] = $this->getAcl()->getUserId(); $data['uploaded_on'] = DateTimeUtils::now()->toString(); $validationConstraints = $this->createConstraintFor($this->collection); + // Do not validate filename when uploading files using URL // The filename will be generate automatically if not defined if (is_a_url(ArrayUtils::get($data, 'data'))) { - unset($validationConstraints['filename']); + unset($validationConstraints['filename_disk']); } + $this->validate($data, array_merge(['data' => 'required'], $validationConstraints)); + $files = $this->container->get('files'); $result=$files->getFileSizeType($data['data']); @@ -56,7 +56,9 @@ public function create(array $data, array $params = []) validate_file($result['size'],'maxSize'); } - $newFile = $tableGateway->createRecord($data, $this->getCRUDParams($params)); + $recordData = $this->getSaveData($data,false); + + $newFile = $tableGateway->createRecord($recordData, $this->getCRUDParams($params)); return $tableGateway->wrapData( \Directus\append_storage_information($newFile->toArray()), @@ -65,6 +67,50 @@ public function create(array $data, array $params = []) ); } + public function getSaveData($data, $isUpdate){ + $dataInfo = []; + $files = $this->container->get('files'); + if (is_a_url($data['data'])) { + $dataInfo = $files->getLink($data['data']); + // Set the URL payload data + $data['data'] = ArrayUtils::get($dataInfo, 'data'); + $data['filename_disk'] = ArrayUtils::get($dataInfo, 'filename_disk'); + } else if (!is_object($data['data'])) { + $dataInfo = $files->getDataInfo($data['data']); + } + + $type = ArrayUtils::get($dataInfo, 'type', ArrayUtils::get($data, 'type')); + + if (strpos($type, 'embed/') === 0) { + $recordData = $files->saveEmbedData(array_merge($dataInfo, ArrayUtils::pick($data, ['filename_disk']))); + } else { + $recordData = $files->saveData($data['data'], $data['filename_disk'],$isUpdate); + } + + // NOTE: Use the user input title, tags, description and location when exists. + $recordData = ArrayUtils::defaults($recordData, ArrayUtils::pick($data, [ + 'title', + 'tags', + 'description', + 'location', + ])); + + if(!$isUpdate){ + $recordData['private_hash'] = get_random_string(); + } + + return ArrayUtils::omit(array_merge($data,$recordData),['data','html']); + } + + protected function findByPrivateHash($hash) + { + $result = $this->createTableGateway(SchemaManager::COLLECTION_FILES, false)->fetchAll(function (Select $select) use ($hash) { + $select->columns(['filename_disk']); + $select->where(['private_hash' => $hash]); + })->current()->toArray(); + return $result; + } + public function find($id, array $params = []) { $tableGateway = $this->createTableGateway($this->collection); @@ -83,7 +129,7 @@ public function findByIds($id, array $params = []) public function update($id, array $data, array $params = []) { $this->enforceUpdatePermissions($this->collection, $data, $params); - + $this->checkItemExists($this->collection, $id); $this->validatePayload($this->collection, array_keys($data), $data, $params); @@ -91,7 +137,7 @@ public function update($id, array $data, array $params = []) if(isset($data['data'])){ $result=$files->getFileSizeType($data['data']); - + if(get_directus_setting('file_mimetype_whitelist') != null){ validate_file($result['mimeType'],'mimeTypes'); } @@ -99,12 +145,29 @@ public function update($id, array $data, array $params = []) validate_file($result['size'],'maxSize'); } } - + $tableGateway = $this->createTableGateway($this->collection); - $newFile = $tableGateway->updateRecord($id, $data, $this->getCRUDParams($params)); + + $currentItem = $tableGateway->getOneData($id); + $currentFileName = ArrayUtils::get($currentItem, 'filename_disk'); + + if ($data['filename_disk'] && $data['filename_disk'] !== $currentFileName) { + $oldFilePath = $currentFileName; + $newFilePath = $data['filename_disk']; + + try { + $this->container->get('filesystem')->getAdapter()->rename($oldFilePath, $newFilePath); + } catch(Exception $e) { + throw new InvalidRequestException($e); + } + } + + $recordData = $this->getSaveData($data, true); + + $newFile = $tableGateway->updateRecord($id, $recordData, $this->getCRUDParams($params)); return $tableGateway->wrapData( - \Directus\append_storage_information($newFile->toArray()), + \Directus\append_storage_information([$newFile->toArray()]), true, ArrayUtils::get($params, 'meta') ); @@ -124,7 +187,7 @@ public function delete($id, array $params = []) $files->delete($file); // Delete file record - return $tableGateway->deleteRecord($id); + return $tableGateway->deleteRecord($id,$this->getCRUDParams($params)); } public function findAll(array $params = []) diff --git a/src/core/Directus/Services/PagesService.php b/src/core/Directus/Services/ModulesService.php similarity index 67% rename from src/core/Directus/Services/PagesService.php rename to src/core/Directus/Services/ModulesService.php index af3f94d6d4..b0d10489cc 100644 --- a/src/core/Directus/Services/PagesService.php +++ b/src/core/Directus/Services/ModulesService.php @@ -4,7 +4,7 @@ use Directus\Application\Container; -class PagesService extends AbstractExtensionsController +class ModulesService extends AbstractExtensionsController { public function __construct(Container $container) { @@ -12,8 +12,8 @@ public function __construct(Container $container) $basePath = $this->container->get('path_base'); $this->paths = [ - $basePath . '/public/extensions/core/pages', - $basePath . '/public/extensions/custom/pages', + $basePath . '/public/extensions/core/modules', + $basePath . '/public/extensions/custom/modules', ]; } diff --git a/src/core/Directus/Services/ProjectService.php b/src/core/Directus/Services/ProjectService.php index 38b17b7e4e..9148314a33 100644 --- a/src/core/Directus/Services/ProjectService.php +++ b/src/core/Directus/Services/ProjectService.php @@ -14,6 +14,7 @@ use Directus\Exception\UnprocessableEntityException; use Directus\Util\ArrayUtils; use Directus\Util\Installation\InstallerUtils; +use Directus\Util\StringUtils; class ProjectService extends AbstractService { @@ -61,10 +62,13 @@ public function create(array $data) // If the first installtion is executing then add the api.json file to store the password. // For every installation after the first one, user must pass that same password to create the next project. - $scannedDirectory = \Directus\scan_config_folder(); + $basePath = \Directus\get_app_base_path(); + $scannedDirectory = \Directus\scan_folder($basePath.'/config'); - $superadminFilePath = \Directus\get_app_base_path().'/config/__api.json'; - if(empty($scannedDirectory)){ + $projectNames = $scannedDirectory; + + $superadminFilePath = $basePath.'/config/__api.json'; + if(empty($projectNames)){ $configStub = InstallerUtils::createJsonFileContent($data); file_put_contents($superadminFilePath, $configStub); }else{ @@ -123,7 +127,7 @@ public function create(array $data) public function delete(Request $request) { $data = $request->getQueryParams(); - + $this->validate($data,[ 'super_admin_token' => 'required', ]); diff --git a/src/core/Directus/Services/ServerService.php b/src/core/Directus/Services/ServerService.php index 5b61d3b52d..33b2d2122d 100644 --- a/src/core/Directus/Services/ServerService.php +++ b/src/core/Directus/Services/ServerService.php @@ -6,6 +6,7 @@ use Directus\Exception\UnauthorizedException; use function Directus\get_project_info; use Directus\Services\UsersService; +use Directus\Util\StringUtils; class ServerService extends AbstractService { @@ -67,10 +68,15 @@ public function findAllInfo($global = true, $configuration = null) */ public function validateServerInfo($data) { - $scannedDirectory = \Directus\scan_config_folder(); - - $superadminFilePath = \Directus\get_app_base_path().'/config/__api.json'; - if(!empty($scannedDirectory)){ + $basePath = \Directus\get_app_base_path(); + + $scannedDirectory = \Directus\scan_folder($basePath.'/config'); + + $projectNames = $scannedDirectory; + + $superadminFilePath = $basePath.'/config/__api.json'; + + if(!empty($projectNames)){ $this->validate($data, [ 'super_admin_token' => 'required' ]); diff --git a/src/core/Directus/Services/SettingsService.php b/src/core/Directus/Services/SettingsService.php index 331c639350..b76946eabb 100644 --- a/src/core/Directus/Services/SettingsService.php +++ b/src/core/Directus/Services/SettingsService.php @@ -3,7 +3,9 @@ namespace Directus\Services; use Directus\Application\Container; +use function Directus\get_directus_setting; use Directus\Database\Schema\SchemaManager; +use Directus\Exception\UnprocessableEntityException; class SettingsService extends AbstractService { diff --git a/src/core/Directus/Services/TablesService.php b/src/core/Directus/Services/TablesService.php index 266b86ba10..79dd9e4dd5 100644 --- a/src/core/Directus/Services/TablesService.php +++ b/src/core/Directus/Services/TablesService.php @@ -746,23 +746,35 @@ public function dropColumn($collectionName, $fieldName, array $params = []) throw new UnprocessableEntityException('Cannot delete the last field'); } - if (!$columnObject->isAlias()) { + if ($columnObject->isAlias() === false) { if (!$this->dropColumnSchema($collectionName, $fieldName)) { throw new ErrorException('Error deleting the field'); } } - if ($columnObject->hasRelationship() && !in_array($columnObject->getType(),DataTypes::getUsersType())) { - $this->removeColumnRelationship($columnObject,$params); + if ( + $columnObject->hasRelationship() && + // Don't remove relational columns for native relationships (users / files) + DataTypes::isUsersType($columnObject->getType()) === false && + DataTypes::isFilesType($columnObject->getType()) === false + ) { + $this->removeColumnRelationship($columnObject, $params); } if ($columnObject->isManaged()) { /** * Remove O2M field if M2O interface deleted as O2M will only work if M2O exist */ - if($columnObject->isManyToOne() && !in_array($columnObject->getType(),DataTypes::getUsersType())){ + + if( + $columnObject->isManyToOne() && + // Don't remove relational columns for native relationships (users / files) + DataTypes::isUsersType($columnObject->getType()) === false && + DataTypes::isFilesType($columnObject->getType()) === false + ) { $this->removeRelatedColumnInfo($columnObject); } + $this->removeColumnInfo($collectionName, $fieldName); } } diff --git a/src/core/Directus/Services/UsersService.php b/src/core/Directus/Services/UsersService.php index e83f6d5489..503634a714 100644 --- a/src/core/Directus/Services/UsersService.php +++ b/src/core/Directus/Services/UsersService.php @@ -25,6 +25,7 @@ use Zend\Db\Sql\Select; use function Directus\get_directus_setting; use Directus\Validator\Exception\InvalidRequestException; +use Zend\Db\TableGateway\TableGateway; class UsersService extends AbstractService { @@ -380,22 +381,26 @@ protected function isLastAdmin($id) public function has2FAEnforced($id) { try { - $result = $this->createTableGateway(SchemaManager::COLLECTION_ROLES, false)->fetchAll(function (Select $select) use ($id) { - $select->columns(['enforce_2fa']); - $select->where(['ur.id' => $id]); - $select->join( - ['ur' => SchemaManager::COLLECTION_USERS], - sprintf('ur.role = %s.id', SchemaManager::COLLECTION_ROLES), - [ - 'role' - ] - ); - - }); - - $enforce_2fa = $result->current()['enforce_2fa']; - - if ($enforce_2fa == null || $enforce_2fa == 0) { + $dbConnection = $this->container->get('database'); + $tableGateway = new TableGateway(SchemaManager::COLLECTION_ROLES, $dbConnection); + $select = new Select(['r' => SchemaManager::COLLECTION_ROLES]); + $select->columns(['enforce_2fa']); + + $subSelect = new Select(['ur' => 'directus_users']); + $subSelect->where->equalTo('ur.id', $id); + $subSelect->limit(1); + + $select->join( + ['ur' => $subSelect], + 'r.id = ur.role', + [ + 'role' + ] + ); + + $result = $tableGateway->selectWith($select)->current()['enforce_2fa']; + + if (empty($result)) { return false; } else { return true; diff --git a/src/core/Directus/Util/DateTimeUtils.php b/src/core/Directus/Util/DateTimeUtils.php index 522547362f..7c72ad7116 100644 --- a/src/core/Directus/Util/DateTimeUtils.php +++ b/src/core/Directus/Util/DateTimeUtils.php @@ -107,18 +107,6 @@ public static function nowInUTC() return static::now('UTC'); } - public static function nowInTimezone() - { - $projectName = \Directus\get_api_project_from_request(); - if(!is_null($projectName)){ - $config = get_project_config($projectName); - return static::now($config->get('app.timezone')); - } else { - // If there's no project config (f.e. when creating projects), default to UTC - return static::now('UTC'); - } - } - /** * Creates a new DateTimeUtils instance from a \DateTime instance * @@ -293,6 +281,9 @@ public function toISO8601Format() return $this->format('c'); } + public function toRFC2616Format() { + return $this->format('D, d M Y H:i:s T'); + } /** * Returns a string format of the datetime * diff --git a/src/core/Directus/Util/Installation/InstallerUtils.php b/src/core/Directus/Util/Installation/InstallerUtils.php index fd0de044cd..8224717567 100644 --- a/src/core/Directus/Util/Installation/InstallerUtils.php +++ b/src/core/Directus/Util/Installation/InstallerUtils.php @@ -31,6 +31,7 @@ class InstallerUtils { const MIGRATION_CONFIGURATION_PATH = '/migrations/migrations.php'; + const MIGRATION_UPGRADE_CONFIGURATION_PATH = '/migrations/migrations.upgrades.php'; /** * Add the upgraded migrations into directus_migration on a fresh installation of project. * Upgraded migrations may contain the same queries which is in db [Original] migrations. @@ -39,9 +40,16 @@ class InstallerUtils * * @return boolean */ - public static function addUpgradeMigrations() + public static function addUpgradeMigrations($basePath = null, $projectName = null) { - $dbConnection = Application::getInstance()->fromContainer('database'); + if(!is_null($basePath) && !is_null($projectName)) + { + $app = static::createApp($basePath, $projectName); + $dbConnection = $app->getContainer()->get('database'); + }else{ + $basePath = \Directus\get_app_base_path(); + $dbConnection = Application::getInstance()->fromContainer('database'); + } $migrationsTableGateway = new TableGateway(SchemaManager::COLLECTION_MIGRATIONS, $dbConnection); $select = new Select($migrationsTableGateway->table); @@ -50,7 +58,7 @@ public static function addUpgradeMigrations() $alreadyStoredMigrations = array_column($result, 'version'); $ignoreableFiles = ['..', '.']; - $scannedDirectory = array_values(array_diff(scandir(\Directus\get_app_base_path().'/migrations/upgrades/schemas'), $ignoreableFiles)); + $scannedDirectory = array_values(array_diff(scandir($basePath.'/migrations/upgrades/schemas'), $ignoreableFiles)); foreach($scannedDirectory as $fileName){ $data = []; $fileNameObject = explode("_",$fileName,2); @@ -58,8 +66,8 @@ public static function addUpgradeMigrations() $data = [ 'version' => $fileNameObject[0], 'migration_name' => $migrationName[0], - 'start_time' => DateTimeUtils::nowInTimezone()->toString(), - 'end_time' => DateTimeUtils::nowInTimezone()->toString() + 'start_time' => DateTimeUtils::nowInUTC()->toString(), + 'end_time' => DateTimeUtils::nowInUTC()->toString() ]; if(!in_array($data['version'],$alreadyStoredMigrations) && !is_null($data['version']) && !is_null($data['migration_name'])){ @@ -227,7 +235,9 @@ public static function runMigrationAndSeeder(Config $config) { $manager = new Manager($config, new StringInput(''), new NullOutput()); $manager->migrate('development'); - $manager->seed('development'); + if(!empty($config['paths']['seeds'])){ + $manager->seed('development'); + } } /** @@ -705,14 +715,11 @@ private static function createConfigFile($path, array $data, $force = false) * * @return Config */ - private static function getMigrationConfig($basePath, $projectName = null, $migrationName = null) + private static function getMigrationConfig($basePath, $projectName = null, $migrationName = 'install') { static::ensureConfigFileExists($basePath, $projectName); static::ensureMigrationFileExists($basePath); - if ($migrationName === null) { - $migrationName = 'db'; - } $configPath = static::createConfigPath($basePath, $projectName); $migrationPath = $basePath . '/migrations/' . $migrationName; @@ -729,9 +736,8 @@ private static function getMigrationConfig($basePath, $projectName = null, $migr ArrayUtils::rename($apiConfig, 'socket', 'unix_socket'); $apiConfig['charset'] = ArrayUtils::get($apiConfig, 'database.charset', 'utf8mb4'); - $configArray = require $basePath.self::MIGRATION_CONFIGURATION_PATH ; - $configArray['paths']['migrations'] = $migrationPath . '/schemas'; - $configArray['paths']['seeds'] = $migrationPath . '/seeds'; + $configArray = $migrationName == "install" ? require $basePath.self::MIGRATION_CONFIGURATION_PATH :require $basePath.self::MIGRATION_UPGRADE_CONFIGURATION_PATH; + $configArray['paths']['migrations'] = $migrationPath; $configArray['environments']['development'] = $apiConfig; return new Config($configArray); @@ -957,8 +963,6 @@ private static function createConfigData(array $data) 'db_password' => null, 'db_socket' => '', 'mail_from' => 'admin@example.com', - 'feedback_token' => sha1(gmdate('U') . StringUtils::randomString(32, false)), - 'feedback_login' => true, 'timezone' => get_default_timezone(), 'logs_path' => __DIR__ . '/../../../../../logs', 'cache' => [ @@ -969,7 +973,7 @@ private static function createConfigData(array $data) 'adapter' => 'local', 'root' => 'public/uploads/{{project}}/originals', 'root_url' => '/uploads/{{project}}/originals', - 'thumb_root' => 'public/uploads/{{project}}/thumbnails', + 'thumb_root' => 'public/uploads/{{project}}/generated', ], 'mail' => [ 'transport' => 'sendmail', diff --git a/src/core/Directus/Util/Installation/stubs/config.stub b/src/core/Directus/Util/Installation/stubs/config.stub index 6613eca69e..84efcb06f1 100644 --- a/src/core/Directus/Util/Installation/stubs/config.stub +++ b/src/core/Directus/Util/Installation/stubs/config.stub @@ -1,17 +1,6 @@ [ - 'env' => 'production', - 'timezone' => '{{timezone}}', - ], - - 'settings' => [ - 'logger' => [ - 'path' => '{{logs_path}}', - ], - ], - 'database' => [ 'type' => '{{db_type}}', 'host' => '{{db_host}}', @@ -21,61 +10,34 @@ return [ 'password' => '{{db_password}}', 'engine' => 'InnoDB', 'charset' => 'utf8mb4', - // When using unix socket to connect to the database the host attribute should be removed - // 'socket' => '/var/lib/mysql/mysql.sock', + // Remove 'host' above when using sockets 'socket' => '{{db_socket}}', ], - 'cache' => [ - 'enabled' => {{cache.enabled}}, - 'response_ttl' => {{cache.response_ttl}}, // seconds - 'pool' => [ - {{optional(cache.adapter)}}, - {{optional(cache.path)}}, - {{optional(cache.host)}}, - {{optional(cache.port)}}, - ], - // 'pool' => [ - // 'adapter' => 'apc' - // ], - // 'pool' => [ - // 'adapter' => 'apcu' - // ], - // 'pool' => [ - // 'adapter' => 'filesystem', - // 'path' => 'cache', // relative to the api directory - // ], - // 'pool' => [ - // 'adapter' => 'memcached', - // //'url' => 'localhost:11211;localhost:11212' - // 'host' => 'localhost', - // 'port' => 11211 - // ], - // 'pool' => [ - // 'adapter' => 'memcache', - // 'url' => 'localhost:11211;localhost:11212' - // //'host' => 'localhost', - // //'port' => 11211 - // ], - // 'pool' => [ - // 'adapter' => 'redis', - // 'host' => 'localhost', - // 'port' => 6379 - // ], + 'cors' => [ + 'enabled' => {{cors.enabled}}, + 'origin' => {{cors.origin}}, + 'methods' => {{cors.methods}}, + 'headers' => {{cors.headers}}, + 'exposed_headers' => {{cors.exposed_headers}}, + 'max_age' => {{cors.max_age}}, + 'credentials' => {{cors.credentials}}, + ], + + 'rate_limit' => [ + 'enabled' => {{rate_limit.enabled}}, + 'limit' => {{rate_limit.limit}}, + 'interval' => {{rate_limit.interval}}, + {{optional(rate_limit.adapter)}}, + {{optional(rate_limit.host)}}, + {{optional(rate_limit.port)}}, + {{optional(rate_limit.timeout)}}, ], 'storage' => [ 'adapter' => '{{storage.adapter}}', - // The storage root is the directus root directory. - // All path are relative to the storage root when the path is not starting with a forward slash. - // By default the uploads directory is located at the directus public root - // An absolute path can be used as alternative. 'root' => '{{storage.root}}', - // This is the url where all the media will be pointing to - // here is where Directus will assume all assets will be accessed - // Ex: (yourdomain)/uploads/_/originals 'root_url' => '{{storage.root_url}}', - // Same as "root", but for the thumbnails 'thumb_root' => '{{storage.thumb_root}}', {{optional(storage.key)}}, {{optional(storage.secret)}}, @@ -83,9 +45,7 @@ return [ {{optional(storage.version)}}, {{optional(storage.bucket)}}, {{optional(storage.options)}}, - // Set custom S3 endpoint {{optional(storage.endpoint)}}, - // Use an internal proxy for downloading all files {{optional(storage.proxy_downloads)}}, ], @@ -102,24 +62,27 @@ return [ ], ], - 'cors' => [ - 'enabled' => {{cors.enabled}}, - 'origin' => {{cors.origin}}, - 'methods' => {{cors.methods}}, - 'headers' => {{cors.headers}}, - 'exposed_headers' => {{cors.exposed_headers}}, - 'max_age' => {{cors.max_age}}, // in seconds - 'credentials' => {{cors.credentials}}, + 'cache' => [ + 'enabled' => {{cache.enabled}}, + 'response_ttl' => {{cache.response_ttl}}, + 'pool' => [ + {{optional(cache.adapter)}}, + {{optional(cache.path)}}, + {{optional(cache.host)}}, + {{optional(cache.port)}}, + ], ], - 'rate_limit' => [ - 'enabled' => {{rate_limit.enabled}}, - 'limit' => {{rate_limit.limit}}, // number of request - 'interval' => {{rate_limit.interval}}, // seconds - {{optional(rate_limit.adapter)}}, - {{optional(rate_limit.host)}}, - {{optional(rate_limit.port)}}, - {{optional(rate_limit.timeout)}}, + 'auth' => [ + 'secret_key' => '{{auth.secret}}', + 'public_key' => '{{auth.public}}', + 'social_providers' => [ + {{optional(auth.social_providers.okta)}}, + {{optional(auth.social_providers.github)}}, + {{optional(auth.social_providers.facebook)}}, + {{optional(auth.social_providers.google)}}, + {{optional(auth.social_providers.twitter)}}, + ], ], 'hooks' => [ @@ -127,43 +90,11 @@ return [ 'filters' => [], ], - 'feedback' => [ - 'token' => '{{feedback_token}}', - 'login' => {{feedback_login}} - ], - - // These tables will not be loaded in the directus schema 'tableBlacklist' => [], - 'auth' => [ - 'secret_key' => '{{auth.secret}}', - 'public_key' => '{{auth.public}}', - {{optional(auth.social_providers)}}, - // 'okta' => [ - // 'client_id' => '', - // 'client_secret' => '', - // 'base_url' => 'https://dev-000000.oktapreview.com/oauth2/default' - // ], - // 'github' => [ - // 'client_id' => '', - // 'client_secret' => '' - // ], - // 'facebook' => [ - // 'client_id' => '', - // 'client_secret' => '', - // 'graph_api_version' => 'v2.8', - // ], - // 'google' => [ - // 'client_id' => '', - // 'client_secret' => '', - // 'hosted_domain' => '*', - // // Uses OpenIDConnect to fetch the email instead of using the Google+ API - // // Disabling the OIDC Mode, requires you to enable the Google+ API otherwise it will fail - // 'use_oidc_mode' => true, - // ], - // 'twitter' => [ - // 'identifier' => '', - // 'secret' => '' - // ] + 'env' => 'production', + + 'logger' => [ + 'path' => '{{logs_path}}', ], ]; diff --git a/src/core/Directus/Util/MimeTypeUtils.php b/src/core/Directus/Util/MimeTypeUtils.php index 4b7027e56e..d438c5a684 100644 --- a/src/core/Directus/Util/MimeTypeUtils.php +++ b/src/core/Directus/Util/MimeTypeUtils.php @@ -2365,7 +2365,7 @@ class MimeTypeUtils 'pcx' => ['image/vnd.zbrush.pcx', 'image/x-pcx'], 'pdb' => ['application/vnd.palm', 'application/x-aportisdoc', 'application/x-palm-database'], 'pdc' => ['application/x-aportisdoc'], - 'pdf' => ['application/acrobat', 'application/nappdf', 'application/pdf', 'application/x-pdf', 'image/pdf'], + 'pdf' => ['application/pdf', 'application/acrobat', 'application/nappdf', 'application/x-pdf', 'image/pdf'], 'pdf.bz2' => ['application/x-bzpdf'], 'pdf.gz' => ['application/x-gzpdf'], 'pdf.lz' => ['application/x-lzpdf'], diff --git a/src/endpoints/Assets.php b/src/endpoints/Assets.php new file mode 100644 index 0000000000..d6938a1918 --- /dev/null +++ b/src/endpoints/Assets.php @@ -0,0 +1,38 @@ +container); + $fileId = $request->getAttribute('id'); + + $asset = $service->getAsset( + $fileId, + $request->getQueryParams() + ); + + if(isset($asset['file']) && $asset['mimeType']) + { + $response->setHeader('Content-type',$asset['mimeType']); + $response->setHeader('Content-Disposition','filename='.$asset['filename_download']); + $response->setHeader('Last-Modified',$asset['last_modified']); + + $body = $response->getBody(); + $body->write($asset['file']); + + return $response; + } + else + { + return $response->withStatus(404); + } + } +} diff --git a/src/endpoints/Auth.php b/src/endpoints/Auth.php index a0c5804873..deef2bfcce 100644 --- a/src/endpoints/Auth.php +++ b/src/endpoints/Auth.php @@ -76,7 +76,7 @@ public function authenticate(Request $request, Response $response) default : $this->storeJwtSession($responseData['data']); } - unset($responseData['data']['user']); + $responseData['data']['user'] = ArrayUtils::omit($responseData['data']['user'], [ 'password' , 'token', 'email_notifications', 'last_access_on', 'last_page']); } $responseData['data'] = !empty($responseData['data']) ? $responseData['data'] : null; @@ -125,7 +125,7 @@ public function storeCookieSession($request,$response,$data){ $userSessionObject = $userSessionService->find(['token' => $accessToken]); $sessionToken = $userSessionObject['token']; }else{ - + $userSession = $userSessionService->create([ 'user' => $data['user']['id'], 'token' => $data['user']['token'], @@ -417,8 +417,14 @@ public function ssoServiceCallback(Request $request, Response $response) $urlParams['attributes'] = $e->getAttributes(); } - $urlParams['code'] = ($e instanceof \Directus\Exception\Exception) ? $e->getErrorCode() : 0; + $urlParams['code'] = ($e instanceof \Directus\Exception\Exception) ? $e->getErrorCode() : -1; $urlParams['error'] = true; + + // Log error to the error file if it's not coming from Directus. This allows the user to debug + // errors coming from the service provider + if ($e instanceof \Directus\Exception\Exception === false) { + $this->container->get('logger')->error($e); + } } diff --git a/src/endpoints/Fields.php b/src/endpoints/Fields.php index d05ee406c7..14819c4858 100644 --- a/src/endpoints/Fields.php +++ b/src/endpoints/Fields.php @@ -169,11 +169,11 @@ public function all(Request $request, Response $response) */ public function delete(Request $request, Response $response) { - + $service = new TablesService($this->container); $field = $service->getFieldObject($request->getAttribute('collection'),$request->getAttribute('field')); - + $service->deleteField( $request->getAttribute('collection'), $request->getAttribute('field'), @@ -191,7 +191,6 @@ public function delete(Request $request, Response $response) $collectionsPermission = $permissionService->findAll($filter); $permissionId = array_column($collectionsPermission['data'], 'id'); $permissionService->batchDeleteWithIds($permissionId); - } return $this->responseWithData($request, $response, []); diff --git a/src/endpoints/Files.php b/src/endpoints/Files.php index 212b5398ed..c3b69fb762 100644 --- a/src/endpoints/Files.php +++ b/src/endpoints/Files.php @@ -25,10 +25,10 @@ class Files extends Route public function __invoke(Application $app) { $app->post('', [$this, 'create']); - $app->get('/{id:' . regex_numeric_ids() . '}', [$this, 'read']); - $app->patch('/{id:' . regex_numeric_ids() . '}', [$this, 'update']); + $app->get('/{id}', [$this, 'read']); + $app->patch('/{id}', [$this, 'update']); $app->patch('', [$this, 'update']); - $app->delete('/{id:' . regex_numeric_ids() . '}', [$this, 'delete']); + $app->delete('/{id}', [$this, 'delete']); $app->get('', [$this, 'all']); // Folders @@ -74,7 +74,8 @@ public function create(Request $request, Response $response) // TODO: the file already exists move it to the upload path location $payload = array_merge([ - 'filename' => $uploadedFile->getClientFilename(), + 'filename_disk' => $uploadedFile->getClientFilename(), + 'filename_download' => $uploadedFile->getClientFilename(), 'data' => $uploadedFile, ], $payload); } @@ -130,7 +131,6 @@ public function update(Request $request, Response $response) $request->getParsedBody(), $request->getQueryParams() ); - return $this->responseWithData($request, $response, $responseData); } diff --git a/src/endpoints/Pages.php b/src/endpoints/Modules.php similarity index 81% rename from src/endpoints/Pages.php rename to src/endpoints/Modules.php index 8c11da8e78..26dbb0b964 100644 --- a/src/endpoints/Pages.php +++ b/src/endpoints/Modules.php @@ -6,9 +6,9 @@ use Directus\Application\Http\Request; use Directus\Application\Http\Response; use Directus\Application\Route; -use Directus\Services\PagesService; +use Directus\Services\ModulesService; -class Pages extends Route +class Modules extends Route { /** * @param Application $app @@ -20,7 +20,7 @@ public function __invoke(Application $app) public function all(Request $request, Response $response) { - $service = new PagesService($this->container); + $service = new ModulesService($this->container); $responseData = $service->findAll(); return $this->responseWithData($request, $response, $responseData); diff --git a/src/endpoints/ProjectHome.php b/src/endpoints/ProjectHome.php index e28ca79e32..2b013bb653 100644 --- a/src/endpoints/ProjectHome.php +++ b/src/endpoints/ProjectHome.php @@ -25,7 +25,7 @@ public function __invoke(Request $request, Response $response) ] ]; } - + return $this->responseWithData($request, $response, $responseData); } } diff --git a/src/endpoints/Server.php b/src/endpoints/Server.php index 564880066b..c65086f22b 100644 --- a/src/endpoints/Server.php +++ b/src/endpoints/Server.php @@ -34,16 +34,27 @@ public function __invoke(Application $app) */ public function projects(Request $request, Response $response) { - $scannedDirectory = \Directus\scan_config_folder(); + // When using Directus in Docker (or any other service that relies on environment variables), always use `_` for + // the project key + if (getenv("DIRECTUS_USE_ENV") === "1") { + $projectNames[] = "_"; + } else { + $basePath = \Directus\get_app_base_path(); + $scannedDirectory = \Directus\scan_folder($basePath.'/config'); - $projectNames = []; - if(empty($scannedDirectory)){ - throw new NotInstalledException('This Directus instance has not been configured. Install via the Directus App (eg: /admin) or read more about configuration at: https://docs.directus.io/getting-started/installation.html#configure'); - }else{ - foreach($scannedDirectory as $fileName){ - if(!StringUtils::startsWith($fileName, 'private.')){ - $fileObject = explode(".",$fileName); - $projectNames[] = $fileObject[0]; + $configFiles = $scannedDirectory; + + if (empty($configFiles)) { + throw new NotInstalledException('This Directus instance has not been configured. Install via the Directus App (eg: /admin) or read more about configuration at: https://docs.directus.io/getting-started/installation.html#configure'); + } + + // We're re-filtering the list of projects again before returning them. This time we'll fetch out the private + // config files. We want to filter out the disabled ones (`_`) so we can correctly return the "No projects installed" + // warning above. + $projectNames = []; + foreach($configFiles as $fileName){ + if (!StringUtils::startsWith($fileName, 'private.')) { + $projectNames[] = explode('.', $fileName)[0]; } } } @@ -81,7 +92,6 @@ public function getInfo(Request $request, Response $response) 'curl' => extension_loaded("curl"), 'gd' => extension_loaded("gd"), 'fileinfo' => extension_loaded("fileinfo"), - 'libapache2_mod_php' => extension_loaded("libapache2-mod-php"), 'mbstring' => extension_loaded("mbstring"), 'json' => extension_loaded("json"), ], diff --git a/src/endpoints/Settings.php b/src/endpoints/Settings.php index 8447753010..0f0f116ec4 100644 --- a/src/endpoints/Settings.php +++ b/src/endpoints/Settings.php @@ -10,6 +10,7 @@ use Directus\Services\FilesServices; use Directus\Util\ArrayUtils; use function Directus\regex_numeric_ids; +use function Directus\get_directus_setting; class Settings extends Route { @@ -35,19 +36,19 @@ public function __invoke(Application $app) */ public function create(Request $request, Response $response) { + $service = new SettingsService($this->container); $this->validateRequestPayload($request); $payload = $request->getParsedBody(); if (isset($payload[0]) && is_array($payload[0])) { return $this->batch($request, $response); } - $service = new SettingsService($this->container); $fieldData = $service->findAllFields( $request->getQueryParams() ); $inputData = $this->getInterfaceBasedInput($request, $payload['key'], $fieldData); - + $responseData = $service->create( $inputData, $request->getQueryParams() @@ -231,6 +232,7 @@ public function update(Request $request, Response $response) } $inputData = $request->getParsedBody(); + $service = new SettingsService($this->container); /** @@ -241,7 +243,6 @@ public function update(Request $request, Response $response) $request->getAttribute('id'), $request->getQueryParams() ); - /** * Get the interface based input * diff --git a/src/helpers/all.php b/src/helpers/all.php index b52639b9c4..c79e99f589 100644 --- a/src/helpers/all.php +++ b/src/helpers/all.php @@ -473,7 +473,7 @@ function get_reserved_endpoint_names() return [ 'server', 'interfaces', - 'pages', + 'modules', 'layouts', 'types', 'projects' @@ -609,7 +609,7 @@ function register_extensions_hooks(Application $app) register_hooks_list( $app, - get_custom_hooks('public/extensions/core/pages', true) + get_custom_hooks('public/extensions/core/modules', true) ); register_hooks_list( @@ -755,15 +755,7 @@ function register_filter_hook(\Directus\Hook\Emitter $emitter, $name, $listener, */ function get_default_timezone(Application $app = null) { - if ($app == null) { - $app = Application::getInstance(); - } - - if (!$app || !($timezone = $app->getConfig()->get('app.timezone'))) { - $timezone = date_default_timezone_get(); - } - - return $timezone; + return date_default_timezone_get(); } } diff --git a/src/helpers/app.php b/src/helpers/app.php index 78ba2cf056..ffa943ce36 100644 --- a/src/helpers/app.php +++ b/src/helpers/app.php @@ -77,7 +77,7 @@ function get_project_config($name, $basePath = null) } $configFilePath = InstallerUtils::createConfigPath($basePath, $name); - + if (isset($configs[$configFilePath])) { return $configs[$configFilePath]; } @@ -116,22 +116,25 @@ function get_app_base_path() } } -if (!function_exists('scan_config_folder')) { +if (!function_exists('scan_folder')) { /** - * Scan config folder and return the php files (Project Configurations) + * Scan folder and return the php files (Project Configurations) * * @return string */ - function scan_config_folder() + function scan_folder($folder) { $projectNames = []; - $ignoreableFiles = ['api_sample.php','.DS_Store','..', '.']; - $scannedDirectory = array_values(array_diff(scandir(get_app_base_path().'/config'), $ignoreableFiles)); - if(!empty($scannedDirectory)){ - foreach($scannedDirectory as $fileName){ - $fileObject = explode(".",$fileName); - if(end($fileObject) == "php" ){ - $projectNames[] = implode(".",$fileObject); + $ignoreableFiles = ['.DS_Store','..', '.']; + $scannedDirectory = array_values(array_diff(scandir($folder), $ignoreableFiles)); + if (!empty($scannedDirectory)) { + foreach ($scannedDirectory as $fileName) { + $fileObject = explode(".", $fileName); + + if (end($fileObject) == "php") { + if (strlen($fileObject[0]) == 1 || StringUtils::startsWith($fileName, '_') === false) { + $projectNames[] = implode(".", $fileObject); + } } } } diff --git a/src/helpers/file.php b/src/helpers/file.php index e102056f87..83bea29337 100644 --- a/src/helpers/file.php +++ b/src/helpers/file.php @@ -129,21 +129,32 @@ function append_storage_information(array $rows) foreach ($rows as &$row) { $data = []; + $ext = pathinfo($row['filename_disk'], PATHINFO_EXTENSION); if ($proxyDownloads) { - $data['url'] = get_proxy_path($row['filename']); + $data['url'] = get_proxy_path($row['filename_disk']); $data['full_url'] = get_url($data['url']); } else { - $data['url'] = $data['full_url'] = $fileRootUrl . '/' . $row['filename']; - - // Add Full url - if ($isLocalStorageAdapter && !$hasFileRootUrlHost) { - $data['full_url'] = get_url($data['url']); + if(isset($row['private_hash'])){ + $data['url'] = $data['full_url'] = $fileRootUrl . '/' . $row['filename_disk']; + // Add Full url + if (!$hasFileRootUrlHost) { + $data['full_url'] = get_url($data['url']); + } } + } - // Add Thumbnails - $data['thumbnails'] = get_thumbnails($row); + // Add thumbnails if the asset is an image + $search = 'image'; + if ( + substr($row['type'], 0, strlen($search)) === $search && + $row['type'] !== 'image/svg+xml' // SVGs aren't manipulatable bitmaps + ) { + $data['thumbnails'] = get_thumbnails($row); + } else { + $data['thumbnails'] = null; + } // Add embed content /** @var \Directus\Embed\EmbedManager $embedManager */ @@ -192,45 +203,36 @@ function add_default_thumbnail_dimensions(array &$list) function get_thumbnails(array $row) { - $filename = $row['filename']; + $filename = $row['filename_disk']; $type = array_get($row, 'type'); $thumbnailFilenameParts = explode('.', $filename); $thumbnailExtension = array_pop($thumbnailFilenameParts); - $thumbnailDimensions = array_filter( - explode(',', get_directus_setting('thumbnail_dimensions')) - ); + + $systemThumb = json_decode(get_directus_setting('asset_whitelist_system'),true); + $whitelistThumb = json_decode(get_directus_setting('asset_whitelist'),true); + $thumbnailWhitelist = !empty($whitelistThumb) ? array_merge($systemThumb, $whitelistThumb) : $systemThumb; $fileExtension = MimeTypeUtils::getFromMimeType($type); + if (!in_array($fileExtension, Thumbnail::getFormatsSupported()) && strpos($type, 'embed/') !== 0) { return null; } - // Add default size - add_default_thumbnail_dimensions($thumbnailDimensions); - $thumbnails = []; - foreach (array_unique($thumbnailDimensions) as $dimension) { + foreach ($thumbnailWhitelist as $thumbnail) { if (Thumbnail::isNonImageFormatSupported($thumbnailExtension)) { $thumbnailExtension = Thumbnail::defaultFormat(); } - if (!is_string($dimension)) { - continue; - } - - $size = explode('x', $dimension); - - if (count($size) == 2) { - $thumbnailUrl = get_thumbnail_url($filename, $size[0], $size[1]); - $thumbnailRelativeUrl = get_thumbnail_path($filename, $size[0], $size[1]); - $thumbnails[] = [ - 'url' => $thumbnailUrl, - 'relative_url' => $thumbnailRelativeUrl, - 'dimension' => $dimension, - 'width' => (int) $size[0], - 'height' => (int) $size[1], - ]; - } + $thumbnailUrl = get_thumbnail_url($row['private_hash'],$thumbnail); + $thumbnailRelativeUrl = get_thumbnail_path($row['private_hash'],$thumbnail); + $thumbnails[] = [ + 'url' => $thumbnailUrl, + 'relative_url' => $thumbnailRelativeUrl, + 'dimension' => $thumbnail['width'].'x'.$thumbnail['height'], + 'width' => (int) $thumbnail['width'], + 'height' => (int) $thumbnail['height'], + ]; } return $thumbnails; @@ -241,17 +243,13 @@ function get_thumbnails(array $row) /** * Returns a url for the given file pointing to the thumbnailer * - * @param string $name - * @param int $width - * @param int $height - * @param string $mode - * @param string $quality + * @param array $thumbnail * * @return string */ - function get_thumbnail_url($name, $width, $height, $mode = 'crop', $quality = 'good') + function get_thumbnail_url($name,$thumbnail) { - return get_url(get_thumbnail_path($name, $width, $height, $mode, $quality)); + return get_url(get_thumbnail_path($name, $thumbnail)); } } @@ -259,27 +257,24 @@ function get_thumbnail_url($name, $width, $height, $mode = 'crop', $quality = 'g /** * Returns a relative url for the given file pointing to the thumbnailer * - * @param string $name - * @param int $width - * @param int $height - * @param string $mode - * @param string $quality + * @param array $thumbnail * * @return string */ - function get_thumbnail_path($name, $width, $height, $mode = 'crop', $quality = 'good') + function get_thumbnail_path($name,$thumbnail) { $projectName = get_api_project_from_request(); - // env/width/height/mode/quality/name + $thumbnailDetail=$thumbnail; + + $paramsString= '?key='.$thumbnailDetail['key']; + return sprintf( - '/thumbnail/%s/%d/%d/%s/%s/%s', + '/%s/%s/%s%s', $projectName, - $width, - $height, - $mode, - $quality, - $name + 'assets', + $name, + $paramsString ); } } @@ -452,3 +447,27 @@ function validate_file_size($value, $options) } } } + +if (!function_exists('get_file_root_url')) { + /** + * Get File Root URL + * + * + * @return string + */ + function get_file_root_url() + { + $container = Application::getInstance()->getContainer(); + $config = $container->get('config'); + return $config->get('storage.root_url'); + } +} + +if (!function_exists('get_random_string')) { + function get_random_string($limit = 16) + { + return substr(base_convert(sha1(uniqid(mt_rand())), 16, 36), 0,$limit); + } +} + + diff --git a/src/helpers/settings.php b/src/helpers/settings.php index ec77c9618c..a109f1abe0 100644 --- a/src/helpers/settings.php +++ b/src/helpers/settings.php @@ -89,11 +89,8 @@ function get_directus_files_settings() function get_directus_thumbnail_settings() { return get_directus_settings_by_keys([ - 'thumbnail_dimensions', - 'thumbnail_not_found_location', - 'thumbnail_quality_tags', - 'thumbnail_actions', - 'thumbnail_cache_ttl', + 'asset_whitelist', + 'asset_whitelist_system' ]); } } diff --git a/src/web.php b/src/web.php index 720a03dec6..91f34c8853 100644 --- a/src/web.php +++ b/src/web.php @@ -71,7 +71,7 @@ $errorReporting = E_ALL; $displayErrors = 1; -if ($app->getConfig()->get('app.env', 'development') === 'production') { +if ($app->getConfig()->get('env', 'development') === 'production') { $displayErrors = $errorReporting = 0; } @@ -135,7 +135,10 @@ ->add($middleware['table_gateway']); +$app->get('/{project}/assets/{id}', \Directus\Api\Routes\Assets::class); + $app->group('/{project}', function () use ($middleware) { + $this->get('/', \Directus\Api\Routes\ProjectHome::class) ->add($middleware['auth_user']) ->add($middleware['rate_limit_user']) @@ -227,8 +230,8 @@ ->add($middleware['auth']) ->add($middleware['table_gateway']); - $this->group('/pages', function () { - $endpointsList = \Directus\get_custom_endpoints('public/extensions/core/pages', true); + $this->group('/modules', function () { + $endpointsList = \Directus\get_custom_endpoints('public/extensions/core/modules', true); foreach ($endpointsList as $name => $endpoints) { \Directus\create_group_route_from_array($this, $name, $endpoints); @@ -268,13 +271,13 @@ ->add($middleware['auth']) ->add($middleware['table_gateway']) ->add($middleware['database_migration']); -$app->group('/pages', \Directus\Api\Routes\Pages::class) +$app->group('/modules', \Directus\Api\Routes\Modules::class) ->add($middleware['rate_limit_user']) ->add($middleware['auth_user']) ->add($middleware['auth']) ->add($middleware['table_gateway']) ->add($middleware['database_migration']); - + $app->group('/server', \Directus\Api\Routes\Server::class); $app->group('/types', \Directus\Api\Routes\Types::class) ->add($middleware['rate_limit_user']) From ec0f12a03afe377893a6a88da9e178161ad031fa Mon Sep 17 00:00:00 2001 From: Rijk van Zanten Date: Thu, 5 Dec 2019 09:44:43 -0500 Subject: [PATCH 02/11] v8.0.1 (#1527) * Fix #1515 [Add type for field] (#1517) * Add migration that ensures filename_download to be set Fixes #1520 * Set a default value for asset whitelist on fresh installations * fix example generated directory * Base filenames on UUID4 instead of UUID5 * Add migration for correct wysiwyg * Fix name of migration file * Fix addUpgradeMigrations (#1524) * Fix addUpgradeMigrations It was reading the wrong folder and therefore didn't run. It also didn't work with ENV mode * FIx whitespace inconsitencies * Add warning if db is already installed * Add check for and support non-env mode in cli db install * Make env check explicit * Update schema.sql demo file * Bump version --- config/_example.php | 2 +- .../20180220023243_create_settings_table.php | 12 + ...0191202164205_update_directus_settings.php | 10 +- ...3105400_add_hash_filedownload_if_empty.php | 43 ++ .../20191204151300_use_correct_wysiwyg.php | 24 + src/core/Directus/Application/Application.php | 2 +- .../Console/Modules/InstallModule.php | 29 +- .../Schema/Sources/AbstractSchema.php | 8 + src/core/Directus/Filesystem/Files.php | 4 +- .../Directus/Services/AbstractService.php | 4 +- .../Util/Installation/InstallerUtils.php | 23 +- src/schema.sql | 524 ++++++++++++------ 12 files changed, 501 insertions(+), 184 deletions(-) create mode 100644 migrations/upgrades/20191203105400_add_hash_filedownload_if_empty.php create mode 100644 migrations/upgrades/20191204151300_use_correct_wysiwyg.php diff --git a/config/_example.php b/config/_example.php index 128fd3541e..4d78499ff5 100644 --- a/config/_example.php +++ b/config/_example.php @@ -58,7 +58,7 @@ // See https://docs.directus.io/extensions/storage-adapters.html#using-aws-s3 'root' => 'public/uploads/project-name/originals', // Where files are stored on disk - 'thumb_root' => 'public/uploads/project-name/thumbnails', // Where thumbnails are stored on disk + 'thumb_root' => 'public/uploads/project-name/generated', // Where thumbnails are stored on disk 'root_url' => '/uploads/project-name/originals', // Where files are accessed over the web 'proxy_downloads' => false, // Use an internal proxy for downloading all files diff --git a/migrations/install/20180220023243_create_settings_table.php b/migrations/install/20180220023243_create_settings_table.php index ab02f55ea1..7223c02ea6 100644 --- a/migrations/install/20180220023243_create_settings_table.php +++ b/migrations/install/20180220023243_create_settings_table.php @@ -435,6 +435,18 @@ public function change() 'key' => 'youtube_api_key', 'value' => '' ], + [ + 'key' => 'asset_whitelist', + 'value' => json_encode([ + [ + "key" => "thumbnail", + "width" => 200, + "height" => 200, + "fit" => "contain", + "quality" => 80 + ] + ]) + ], [ 'key' => 'asset_whitelist_system', 'value' => json_encode([ diff --git a/migrations/upgrades/20191202164205_update_directus_settings.php b/migrations/upgrades/20191202164205_update_directus_settings.php index 74fcd232e9..53f4370bdb 100644 --- a/migrations/upgrades/20191202164205_update_directus_settings.php +++ b/migrations/upgrades/20191202164205_update_directus_settings.php @@ -94,7 +94,15 @@ public function change() { ], [ 'key' => 'asset_whitelist', - 'value' => '' + 'value' => json_encode([ + [ + "key" => "thumbnail", + "width" => 200, + "height" => 200, + "fit" => "contain", + "quality" => 80 + ] + ]) ] ]; diff --git a/migrations/upgrades/20191203105400_add_hash_filedownload_if_empty.php b/migrations/upgrades/20191203105400_add_hash_filedownload_if_empty.php new file mode 100644 index 0000000000..aa391d4db4 --- /dev/null +++ b/migrations/upgrades/20191203105400_add_hash_filedownload_if_empty.php @@ -0,0 +1,43 @@ +table('directus_files'); + + // ------------------------------------------------------------------------- + // Add a private hash for all existing files + // ------------------------------------------------------------------------- + $filesWithoutPrivateHash = $this->fetchAll('SELECT id FROM directus_files WHERE private_hash IS NULL OR private_hash = "";'); + + foreach($filesWithoutPrivateHash as $key => $value) { + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_files', + ['private_hash' => get_random_string()], + ['id' => $value['id']] + )); + } + + // ------------------------------------------------------------------------- + // Add a private hash for all existing files + // ------------------------------------------------------------------------- + $filesWithoutFiledownload = $this->fetchAll('SELECT id, filename_disk FROM directus_files WHERE filename_download IS NULL OR filename_download = "";'); + + foreach($filesWithoutFiledownload as $key => $value) { + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_files', + ['filename_download' => $value['filename_disk']], + ['id' => $value['id']] + )); + } + + // ------------------------------------------------------------------------- + // Save changes to table + // ------------------------------------------------------------------------- + $filesTable->save(); + } +} diff --git a/migrations/upgrades/20191204151300_use_correct_wysiwyg.php b/migrations/upgrades/20191204151300_use_correct_wysiwyg.php new file mode 100644 index 0000000000..b38419454f --- /dev/null +++ b/migrations/upgrades/20191204151300_use_correct_wysiwyg.php @@ -0,0 +1,24 @@ +execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + ['interface' => 'wysiwyg'], + ['interface' => 'wysiwyg-advanced'] + )); + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + ['interface' => 'wysiwyg'], + ['interface' => 'wysiwyg-full'] + )); + } +} diff --git a/src/core/Directus/Application/Application.php b/src/core/Directus/Application/Application.php index c6ab4d77a8..0f26314fa8 100644 --- a/src/core/Directus/Application/Application.php +++ b/src/core/Directus/Application/Application.php @@ -13,7 +13,7 @@ class Application extends App * * @var string */ - const DIRECTUS_VERSION = '8.0.0'; + const DIRECTUS_VERSION = '8.0.1'; /** * NOT USED diff --git a/src/core/Directus/Console/Modules/InstallModule.php b/src/core/Directus/Console/Modules/InstallModule.php index 0eb65521b0..f9dd47ab36 100644 --- a/src/core/Directus/Console/Modules/InstallModule.php +++ b/src/core/Directus/Console/Modules/InstallModule.php @@ -2,8 +2,10 @@ namespace Directus\Console\Modules; +use Directus\Database\Exception\ConnectionFailedException; use Directus\Console\Common\Exception\PasswordChangeException; use Directus\Console\Common\Exception\UserUpdateException; +use Directus\Console\Common\Exception\InvalidDatabaseConnectionException; use Directus\Console\Common\Setting; use Directus\Console\Common\User; use Directus\Console\Exception\CommandFailedException; @@ -154,7 +156,7 @@ public function cmdConfig($args, $extra) public function cmdDatabase($args, $extra) { - $directus_path = $this->getBasePath() . DIRECTORY_SEPARATOR; + $directus_path = $this->getBasePath(); $projectName = null; $force = false; @@ -172,6 +174,31 @@ public function cmdDatabase($args, $extra) } } + + if (getenv('DIRECTUS_USE_ENV') === "1") { + $data = [ + 'project' => '_', + 'db_name' => getenv('DIRECTUS_DATABASE_NAME'), + 'db_host' => getenv('DIRECTUS_DATABASE_HOST'), + 'db_port' => getenv('DIRECTUS_DATABASE_PORT'), + 'db_user' => getenv('DIRECTUS_DATABASE_USERNAME'), + 'db_password' => getenv('DIRECTUS_DATABASE_PASSWORD'), + ]; + } else { + $app = InstallerUtils::createApp($directus_path, $projectName); + $config = $app->getConfig(); + $data = [ + 'project' => $projectName, + 'db_name' => $config['database']['name'], + 'db_host' => $config['database']['host'], + 'db_port' => $config['database']['port'], + 'db_user' => $config['database']['username'], + 'db_password' => $config['database']['password'], + ]; + } + + InstallerUtils::ensureCanCreateTables($directus_path, $data, $force); + InstallerUtils::createTables($directus_path, $projectName, $force); InstallerUtils::addUpgradeMigrations($this->getBasePath(),$projectName); } diff --git a/src/core/Directus/Database/Schema/Sources/AbstractSchema.php b/src/core/Directus/Database/Schema/Sources/AbstractSchema.php index 16b7e158a0..38734b494a 100644 --- a/src/core/Directus/Database/Schema/Sources/AbstractSchema.php +++ b/src/core/Directus/Database/Schema/Sources/AbstractSchema.php @@ -130,16 +130,24 @@ public function getTypeFromSource($sourceType) case 'tinyint': case 'smallint': case 'mediumint': + case 'bigint': + case 'serial': case 'int': // alias: integer case 'year': $type = DataTypes::TYPE_INTEGER; break; case 'decimal': // alias: dec, fixed case 'numeric': + case 'real': case 'float': // alias: real case 'double': // alias: double precision, real $type = DataTypes::TYPE_DECIMAL; break; + case 'bool': + case 'boolean': + $type = DataTypes::TYPE_BOOLEAN; + case 'blob': + case 'longblob': case 'bit': case 'binary': case 'varbinary': diff --git a/src/core/Directus/Filesystem/Files.php b/src/core/Directus/Filesystem/Files.php index 2440cc60a4..c49af8220c 100644 --- a/src/core/Directus/Filesystem/Files.php +++ b/src/core/Directus/Filesystem/Files.php @@ -5,7 +5,7 @@ use Char0n\FFMpegPHP\Movie; use Directus\Application\Application; use function Directus\filename_put_ext; -use function Directus\generate_uuid5; +use function Directus\generate_uuid4; use function Directus\is_a_url; use Directus\Util\ArrayUtils; use Directus\Util\DateTimeUtils; @@ -709,7 +709,7 @@ private function getFileName($fileName, $unique = true) private function uuidFileName($fileName) { $ext = pathinfo($fileName, PATHINFO_EXTENSION); - $fileHashName = generate_uuid5(null, $fileName); + $fileHashName = generate_uuid4(); return $fileHashName . '.' . $ext; } diff --git a/src/core/Directus/Services/AbstractService.php b/src/core/Directus/Services/AbstractService.php index 4da5f078d8..e1a01e86f3 100644 --- a/src/core/Directus/Services/AbstractService.php +++ b/src/core/Directus/Services/AbstractService.php @@ -541,8 +541,8 @@ protected function validateFieldLength($field, $value) sprintf("The value submitted (%s) for '%s' is longer than the field's supported length (%s). Please submit a shorter value or ask an Admin to increase the length.",$value,$field->getFormatisedName(),$field['length']) ); } - }else{ - if(!is_null($field['length']) && ((is_array($value) && $field['length'] < strlen(json_encode($value))) || (!is_array($value) && $field['length'] < strlen($value)))){ + } else { + if (!is_null($field['length']) && ((is_array($value) && $field['length'] < strlen(json_encode($value))) || (!is_array($value) && $field['length'] < mb_strlen($value, 'UTF-8')))){ throw new UnprocessableEntityException( sprintf("The value submitted (%s) for '%s' is longer than the field's supported length (%s). Please submit a shorter value or ask an Admin to increase the length.",!is_array($value) ? $value : 'Json / Array',$field->getFormatisedName(),$field['length']) ); diff --git a/src/core/Directus/Util/Installation/InstallerUtils.php b/src/core/Directus/Util/Installation/InstallerUtils.php index 8224717567..d27da2f91d 100644 --- a/src/core/Directus/Util/Installation/InstallerUtils.php +++ b/src/core/Directus/Util/Installation/InstallerUtils.php @@ -42,14 +42,18 @@ class InstallerUtils */ public static function addUpgradeMigrations($basePath = null, $projectName = null) { - if(!is_null($basePath) && !is_null($projectName)) - { + + if ( + static::isUsingFiles() == false || + (!is_null($basePath) && !is_null($projectName)) + ) { $app = static::createApp($basePath, $projectName); - $dbConnection = $app->getContainer()->get('database'); - }else{ + $dbConnection = $app->getContainer()->get('database'); + } else { $basePath = \Directus\get_app_base_path(); $dbConnection = Application::getInstance()->fromContainer('database'); } + $migrationsTableGateway = new TableGateway(SchemaManager::COLLECTION_MIGRATIONS, $dbConnection); $select = new Select($migrationsTableGateway->table); @@ -57,12 +61,13 @@ public static function addUpgradeMigrations($basePath = null, $projectName = nul $result = $migrationsTableGateway->selectWith($select)->toArray(); $alreadyStoredMigrations = array_column($result, 'version'); - $ignoreableFiles = ['..', '.']; - $scannedDirectory = array_values(array_diff(scandir($basePath.'/migrations/upgrades/schemas'), $ignoreableFiles)); + $ignoreableFiles = ['..', '.', '.DS_Store']; + $scannedDirectory = array_values(array_diff(scandir($basePath.'/migrations/upgrades'), $ignoreableFiles)); foreach($scannedDirectory as $fileName){ $data = []; - $fileNameObject = explode("_",$fileName,2); - $migrationName = explode(".",str_replace(' ', '',ucwords(str_replace('_', ' ', $fileNameObject[1]))),2); + $fileNameObject = explode("_", $fileName, 2); + $migrationName = explode(".", str_replace(' ', '', ucwords(str_replace('_', ' ', $fileNameObject[1]))), 2); + $data = [ 'version' => $fileNameObject[0], 'migration_name' => $migrationName[0], @@ -173,6 +178,8 @@ public static function replacePlaceholderValues($content, $data) * * @param string $path * @param array $data + * The JSON that the user POSTed to the create-project endpoint + * Required in here are the database credentials * @param bool $force */ public static function ensureCanCreateTables($path, array $data, $force = false) diff --git a/src/schema.sql b/src/schema.sql index dfe72e0a17..cd613a8705 100644 --- a/src/schema.sql +++ b/src/schema.sql @@ -1,61 +1,40 @@ -/* -SQLyog Ultimate v12.09 (64 bit) -MySQL - 5.7.21-log : Database - directus-live -********************************************************************* -*/ - - +-- ------------------------------------------------------------- +-- TablePlus 2.11.2(278) +-- +-- https://tableplus.com/ +-- +-- Database: db +-- Generation Time: 2019-12-05 09:39:38.1110 +-- ------------------------------------------------------------- + + +/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; +/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; +/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; /*!40101 SET NAMES utf8 */; - -/*!40101 SET SQL_MODE=''*/; - +/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */; +/*!40103 SET TIME_ZONE='+00:00' */; /*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */; /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; -/*Table structure for table `directus_activity` */ - -DROP TABLE IF EXISTS `directus_activity`; CREATE TABLE `directus_activity` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `action` varchar(45) NOT NULL, - `action_by` int(11) unsigned NOT NULL DEFAULT '0', + `action_by` int(11) unsigned NOT NULL DEFAULT 0, `action_on` datetime NOT NULL, `ip` varchar(50) NOT NULL, `user_agent` varchar(255) NOT NULL, `collection` varchar(64) NOT NULL, `item` varchar(255) NOT NULL, `edited_on` datetime DEFAULT NULL, - `comment` text CHARACTER SET utf8mb4, + `comment` text CHARACTER SET utf8mb4 DEFAULT NULL, `comment_deleted_on` datetime DEFAULT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; - -/*Data for the table `directus_activity` */ - -insert into `directus_activity`(`id`,`action`,`action_by`,`action_on`,`ip`,`user_agent`,`collection`,`item`,`edited_on`,`comment`,`comment_deleted_on`) values (1,'authenticate',1,'2019-06-22 07:28:21','::1','Mozilla/5.0 (Windows NT 6.3; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/75.0.3770.100 Safari/537.36','directus_users','1',NULL,NULL,NULL); - -/*Table structure for table `directus_activity_seen` */ - -DROP TABLE IF EXISTS `directus_activity_seen`; - -CREATE TABLE `directus_activity_seen` ( - `id` int(11) unsigned NOT NULL AUTO_INCREMENT, - `activity` int(11) unsigned NOT NULL, - `user` int(11) unsigned NOT NULL DEFAULT '0', - `seen_on` datetime DEFAULT NULL, - `archived` tinyint(1) unsigned NOT NULL DEFAULT '0', - PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -/*Data for the table `directus_activity_seen` */ - -/*Table structure for table `directus_collection_presets` */ - -DROP TABLE IF EXISTS `directus_collection_presets`; - CREATE TABLE `directus_collection_presets` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `title` varchar(255) CHARACTER SET utf8mb4 DEFAULT NULL, @@ -63,99 +42,73 @@ CREATE TABLE `directus_collection_presets` ( `role` int(11) unsigned DEFAULT NULL, `collection` varchar(64) NOT NULL, `search_query` varchar(100) DEFAULT NULL, - `filters` text, + `filters` text DEFAULT NULL, `view_type` varchar(100) NOT NULL DEFAULT 'tabular', - `view_query` text, - `view_options` text, - `translation` text, + `view_query` text DEFAULT NULL, + `view_options` text DEFAULT NULL, + `translation` text DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx_user_collection_title` (`user`,`collection`,`title`) -) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8; - -/*Data for the table `directus_collection_presets` */ - -insert into `directus_collection_presets`(`id`,`title`,`user`,`role`,`collection`,`search_query`,`filters`,`view_type`,`view_query`,`view_options`,`translation`) values (1,NULL,NULL,NULL,'directus_activity',NULL,NULL,'timeline','{\"timeline\":{\"sort\":\"-action_on\"}}','{\"timeline\":{\"date\":\"action_on\",\"title\":\"{{ action_by.first_name }} {{ action_by.last_name }} ({{ action }})\",\"content\":\"action_by\",\"color\":\"action\"}}',NULL),(2,NULL,NULL,NULL,'directus_files',NULL,NULL,'cards',NULL,'{\"cards\":{\"title\":\"title\",\"subtitle\":\"type\",\"content\":\"description\",\"src\":\"data\"}}',NULL),(3,NULL,NULL,NULL,'directus_users',NULL,NULL,'cards',NULL,'{\"cards\":{\"title\":\"first_name\",\"subtitle\":\"last_name\",\"content\":\"title\",\"src\":\"avatar\",\"icon\":\"person\"}}',NULL); - -/*Table structure for table `directus_collections` */ - -DROP TABLE IF EXISTS `directus_collections`; +) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=utf8; CREATE TABLE `directus_collections` ( `collection` varchar(64) NOT NULL, - `managed` tinyint(1) unsigned NOT NULL DEFAULT '1', - `hidden` tinyint(1) unsigned NOT NULL DEFAULT '0', - `single` tinyint(1) unsigned NOT NULL DEFAULT '0', + `managed` tinyint(1) unsigned NOT NULL DEFAULT 1, + `hidden` tinyint(1) unsigned NOT NULL DEFAULT 0, + `single` tinyint(1) unsigned NOT NULL DEFAULT 0, `icon` varchar(30) DEFAULT NULL, `note` varchar(255) DEFAULT NULL, - `translation` text, + `translation` text DEFAULT NULL, PRIMARY KEY (`collection`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -/*Data for the table `directus_collections` */ - -/*Table structure for table `directus_fields` */ - -DROP TABLE IF EXISTS `directus_fields`; - CREATE TABLE `directus_fields` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `collection` varchar(64) NOT NULL, `field` varchar(64) NOT NULL, `type` varchar(64) NOT NULL, `interface` varchar(64) DEFAULT NULL, - `options` text, - `locked` tinyint(1) unsigned NOT NULL DEFAULT '0', + `options` text DEFAULT NULL, + `locked` tinyint(1) unsigned NOT NULL DEFAULT 0, `validation` varchar(255) DEFAULT NULL, - `required` tinyint(1) unsigned NOT NULL DEFAULT '0', - `readonly` tinyint(1) unsigned NOT NULL DEFAULT '0', - `hidden_detail` tinyint(1) unsigned NOT NULL DEFAULT '0', - `hidden_browse` tinyint(1) unsigned NOT NULL DEFAULT '0', + `required` tinyint(1) unsigned NOT NULL DEFAULT 0, + `readonly` tinyint(1) unsigned NOT NULL DEFAULT 0, + `hidden_detail` tinyint(1) unsigned NOT NULL DEFAULT 0, + `hidden_browse` tinyint(1) unsigned NOT NULL DEFAULT 0, `sort` int(11) unsigned DEFAULT NULL, - `width` varchar(30) DEFAULT NULL, + `width` varchar(50) DEFAULT 'full', `group` int(11) unsigned DEFAULT NULL, `note` varchar(1024) DEFAULT NULL, - `translation` text, + `translation` text DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx_collection_field` (`collection`,`field`) -) ENGINE=InnoDB AUTO_INCREMENT=145 DEFAULT CHARSET=utf8; - -/*Data for the table `directus_fields` */ - -insert into `directus_fields`(`id`,`collection`,`field`,`type`,`interface`,`options`,`locked`,`validation`,`required`,`readonly`,`hidden_detail`,`hidden_browse`,`sort`,`width`,`group`,`note`,`translation`) values (1,'directus_activity','id','integer','primary-key',NULL,1,NULL,1,1,1,0,NULL,'full',NULL,NULL,NULL),(2,'directus_activity','action','string','activity-icon',NULL,1,NULL,0,1,0,0,1,'full',NULL,NULL,NULL),(3,'directus_activity','collection','string','collections',NULL,1,NULL,0,1,0,0,2,'half',NULL,NULL,NULL),(4,'directus_activity','item','string','text-input',NULL,1,NULL,0,1,0,0,3,'half',NULL,NULL,NULL),(5,'directus_activity','action_by','integer','user',NULL,1,NULL,0,1,0,0,4,'half',NULL,NULL,NULL),(6,'directus_activity','action_on','datetime','datetime','{\"showRelative\":true}',1,NULL,0,1,0,0,5,'half',NULL,NULL,NULL),(7,'directus_activity','edited_on','datetime','datetime','{\"showRelative\":true}',1,NULL,0,1,0,0,6,'half',NULL,NULL,NULL),(8,'directus_activity','comment_deleted_on','datetime','datetime','{\"showRelative\":true}',1,NULL,0,1,0,0,7,'half',NULL,NULL,NULL),(9,'directus_activity','ip','string','text-input',NULL,1,NULL,0,1,0,0,8,'half',NULL,NULL,NULL),(10,'directus_activity','user_agent','string','text-input',NULL,1,NULL,0,1,0,0,9,'half',NULL,NULL,NULL),(11,'directus_activity','comment','string','textarea',NULL,1,NULL,0,1,0,0,10,'full',NULL,NULL,NULL),(12,'directus_collection_presets','id','integer','primary-key',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(13,'directus_collection_presets','title','string','text-input',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(14,'directus_collection_presets','user','integer','user',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(15,'directus_collection_presets','role','m2o','many-to-one',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(16,'directus_collection_presets','collection','m2o','many-to-one',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(17,'directus_collection_presets','search_query','string','text-input',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(18,'directus_collection_presets','filters','json','json',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(19,'directus_collection_presets','view_options','json','json',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(20,'directus_collection_presets','view_type','string','text-input',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(21,'directus_collection_presets','view_query','json','json',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(22,'directus_collections','fields','o2m','one-to-many',NULL,1,NULL,0,0,1,1,1,'full',NULL,NULL,NULL),(23,'directus_collections','collection','string','primary-key',NULL,1,NULL,1,1,0,0,2,'half',NULL,NULL,NULL),(24,'directus_collections','note','string','text-input',NULL,1,NULL,0,0,0,0,3,'half',NULL,'An internal description.',NULL),(25,'directus_collections','managed','boolean','toggle',NULL,1,NULL,0,0,1,0,4,'half',NULL,'[Learn More](https://docs.directus.io/guides/collections.html#managing-collections).',NULL),(26,'directus_collections','hidden','boolean','toggle',NULL,1,NULL,0,0,0,0,5,'half',NULL,'[Learn More](https://docs.directus.io/guides/collections.html#hidden).',NULL),(27,'directus_collections','single','boolean','toggle',NULL,1,NULL,0,0,0,0,6,'half',NULL,'[Learn More](https://docs.directus.io/guides/collections.html#single).',NULL),(28,'directus_collections','translation','json','json',NULL,1,NULL,0,0,1,0,7,'full',NULL,NULL,NULL),(29,'directus_collections','icon','string','icon',NULL,1,NULL,0,0,0,0,8,'full',NULL,'The icon shown in the App\'s navigation sidebar.',NULL),(30,'directus_fields','id','integer','primary-key',NULL,1,NULL,1,0,1,0,NULL,'full',NULL,NULL,NULL),(31,'directus_fields','collection','m2o','many-to-one',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(32,'directus_fields','field','string','text-input',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(33,'directus_fields','type','string','primary-key',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(34,'directus_fields','interface','string','primary-key',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(35,'directus_fields','options','json','json',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(36,'directus_fields','locked','boolean','toggle',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(37,'directus_fields','translation','json','json',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(38,'directus_fields','readonly','boolean','toggle',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(39,'directus_fields','validation','string','text-input',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(40,'directus_fields','required','boolean','toggle',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(41,'directus_fields','sort','sort','sort',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(42,'directus_fields','note','string','text-input',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(43,'directus_fields','hidden_detail','boolean','toggle',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(44,'directus_fields','hidden_browse','boolean','toggle',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(45,'directus_fields','width','integer','numeric',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(46,'directus_fields','group','m2o','many-to-one',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(47,'directus_files','data','alias','file',NULL,1,NULL,0,0,1,0,0,'full',NULL,NULL,NULL),(48,'directus_files','id','integer','primary-key',NULL,1,NULL,1,0,1,0,1,'full',NULL,NULL,NULL),(49,'directus_files','preview','alias','file-preview',NULL,1,NULL,0,0,0,0,2,'full',NULL,NULL,NULL),(50,'directus_files','title','string','text-input','{\"placeholder\":\"Enter a descriptive title...\",\"iconRight\":\"title\"}',1,NULL,0,0,0,0,3,'half',NULL,NULL,NULL),(51,'directus_files','filename','string','text-input','{\"placeholder\":\"Enter a unique file name...\",\"iconRight\":\"insert_drive_file\"}',1,NULL,1,1,0,0,4,'half',NULL,NULL,NULL),(52,'directus_files','tags','array','tags',NULL,0,NULL,0,0,0,0,5,'half',NULL,NULL,NULL),(53,'directus_files','location','string','text-input','{\"placeholder\":\"Enter a location...\",\"iconRight\":\"place\"}',0,NULL,0,0,0,0,6,'half',NULL,NULL,NULL),(54,'directus_files','description','string','wysiwyg','{\"placeholder\":\"Enter a caption or description...\"}',0,NULL,0,0,0,0,7,'full',NULL,NULL,NULL),(55,'directus_files','width','integer','numeric','{\"iconRight\":\"straighten\"}',1,NULL,0,1,0,0,10,'half',NULL,NULL,NULL),(56,'directus_files','height','integer','numeric','{\"iconRight\":\"straighten\"}',1,NULL,0,1,0,0,11,'half',NULL,NULL,NULL),(57,'directus_files','duration','integer','numeric','{\"iconRight\":\"timer\"}',1,NULL,0,1,0,0,12,'half',NULL,NULL,NULL),(58,'directus_files','filesize','integer','file-size','{\"iconRight\":\"storage\"}',1,NULL,0,1,0,0,13,'half',NULL,NULL,NULL),(59,'directus_files','uploaded_on','datetime','datetime','{\"iconRight\":\"today\"}',1,NULL,1,1,0,0,8,'half',NULL,NULL,NULL),(60,'directus_files','uploaded_by','integer','user',NULL,1,NULL,1,1,0,0,9,'half',NULL,NULL,NULL),(61,'directus_files','metadata','json','json',NULL,1,NULL,0,0,0,0,14,'full',NULL,NULL,NULL),(62,'directus_files','type','string','text-input',NULL,1,NULL,0,1,1,0,NULL,'full',NULL,NULL,NULL),(63,'directus_files','charset','string','text-input',NULL,1,NULL,0,1,1,1,NULL,'full',NULL,NULL,NULL),(64,'directus_files','embed','string','text-input',NULL,1,NULL,0,1,1,0,NULL,'full',NULL,NULL,NULL),(65,'directus_files','folder','m2o','many-to-one',NULL,1,NULL,0,0,1,0,NULL,'full',NULL,NULL,NULL),(66,'directus_files','storage','string','text-input',NULL,1,NULL,0,0,1,1,NULL,'full',NULL,NULL,NULL),(67,'directus_files','checksum','string','text-input',NULL,1,NULL,0,1,1,1,NULL,'full',NULL,NULL,NULL),(68,'directus_folders','id','integer','primary-key',NULL,1,NULL,1,0,1,0,NULL,'full',NULL,NULL,NULL),(69,'directus_folders','name','string','text-input',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(70,'directus_folders','parent_folder','m2o','many-to-one',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(71,'directus_permissions','id','integer','primary-key',NULL,1,NULL,1,0,1,0,NULL,'full',NULL,NULL,NULL),(72,'directus_permissions','collection','m2o','many-to-one',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(73,'directus_permissions','role','m2o','many-to-one',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(74,'directus_permissions','status','string','text-input',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(75,'directus_permissions','create','string','text-input',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(76,'directus_permissions','read','string','text-input',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(77,'directus_permissions','update','string','text-input',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(78,'directus_permissions','delete','string','primary-key',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(79,'directus_permissions','comment','string','text-input',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(80,'directus_permissions','explain','string','text-input',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(81,'directus_permissions','status_blacklist','array','tags',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(82,'directus_permissions','read_field_blacklist','array','tags',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(83,'directus_permissions','write_field_blacklist','array','tags',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(84,'directus_relations','id','integer','primary-key',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(85,'directus_relations','collection_many','string','collections',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(86,'directus_relations','field_many','string','text-input',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(87,'directus_relations','collection_one','string','collections',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(88,'directus_relations','field_one','string','text-input',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(89,'directus_relations','junction_field','string','text-input',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(90,'directus_revisions','id','integer','primary-key',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(91,'directus_revisions','activity','m2o','many-to-one',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(92,'directus_revisions','collection','m2o','many-to-one',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(93,'directus_revisions','item','string','text-input',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(94,'directus_revisions','data','json','json',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(95,'directus_revisions','delta','json','json',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(96,'directus_revisions','parent_item','string','text-input',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(97,'directus_revisions','parent_collection','string','collections',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(98,'directus_revisions','parent_changed','boolean','toggle',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(99,'directus_roles','id','integer','primary-key',NULL,1,NULL,1,0,1,0,NULL,'full',NULL,NULL,NULL),(100,'directus_roles','external_id','string','text-input',NULL,1,NULL,0,1,1,1,NULL,'full',NULL,NULL,NULL),(101,'directus_roles','name','string','text-input',NULL,1,NULL,1,0,0,0,1,'half',NULL,NULL,NULL),(102,'directus_roles','description','string','text-input',NULL,1,NULL,0,0,0,0,2,'half',NULL,NULL,NULL),(103,'directus_roles','ip_whitelist','string','textarea',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(104,'directus_roles','nav_blacklist','string','textarea',NULL,1,NULL,0,0,1,1,NULL,'full',NULL,NULL,NULL),(105,'directus_roles','users','o2m','many-to-many','{\"fields\":\"first_name,last_name\"}',1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(106,'directus_roles','nav_override','json','json','[\r\n {\r\n \"title\": \"$t:collections\",\r\n \"include\": \"collections\"\r\n },\r\n {\r\n \"title\": \"$t:bookmarks\",\r\n \"include\": \"bookmarks\"\r\n },\r\n {\r\n \"title\": \"$t:extensions\",\r\n \"include\": \"extensions\"\r\n },\r\n {\r\n \"title\": \"Custom Links\",\r\n \"links\": [\r\n {\r\n \"name\": \"RANGER Studio\",\r\n \"path\": \"https://rangerstudio.com\",\r\n \"icon\": \"star\"\r\n },\r\n {\r\n \"name\": \"Movies\",\r\n \"path\": \"/collections/movies\"\r\n }\r\n ]\r\n }\r\n ]',1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(107,'directus_settings','project_name','string','text-input',NULL,1,NULL,1,0,0,0,1,'half-space',NULL,NULL,NULL),(108,'directus_settings','color','string','color-palette',NULL,1,NULL,0,0,0,0,2,'half',NULL,'How many minutes before an idle user is signed out.',NULL),(109,'directus_settings','logo','file','file',NULL,1,NULL,0,0,0,0,3,'half',NULL,'Your brand\'s logo.',NULL),(110,'directus_settings','app_url','string','text-input',NULL,1,NULL,1,0,0,0,4,'half-space',NULL,'The URL where your app is hosted. The API will use this to direct your users to the correct login page.',NULL),(111,'directus_settings','default_limit','integer','numeric',NULL,1,NULL,1,0,0,0,5,'half',NULL,'How many minutes before an idle user is signed out.',NULL),(112,'directus_settings','sort_null_last','boolean','toggle',NULL,1,NULL,0,0,0,0,6,'half-space',NULL,'Put items with `null` for the value last when sorting.',NULL),(113,'directus_settings','auto_sign_out','integer','numeric',NULL,1,NULL,1,0,0,0,7,'half',NULL,'How many minutes before an idle user is signed out.',NULL),(114,'directus_settings','youtube_api','string','text-input',NULL,1,NULL,0,0,0,0,8,'half',NULL,'When provided, this allows more information to be collected for YouTube embeds.',NULL),(115,'directus_settings','thumbnail_dimensions','array','tags',NULL,1,NULL,0,0,0,0,9,'full',NULL,'Allowed dimensions for thumbnails.',NULL),(116,'directus_settings','thumbnail_quality_tags','json','json',NULL,1,NULL,0,0,0,0,10,'half',NULL,'Allowed quality for thumbnails.',NULL),(117,'directus_settings','thumbnail_actions','json','json',NULL,1,NULL,0,0,0,0,11,'half',NULL,'Defines how the thumbnail will be generated based on the requested dimensions.',NULL),(118,'directus_settings','thumbnail_cache_ttl','integer','numeric',NULL,1,NULL,1,0,0,0,12,'half',NULL,'`max-age` HTTP header of the thumbnail.',NULL),(119,'directus_settings','thumbnail_not_found_location','string','text-input',NULL,1,NULL,0,0,0,0,13,'half',NULL,'This image will be used when trying to generate a thumbnail with invalid options or an error happens on the server when creating the image.',NULL),(120,'directus_users','id','integer','primary-key',NULL,1,NULL,1,0,1,0,1,'full',NULL,NULL,NULL),(121,'directus_users','status','status','status','{\"status_mapping\":{\"draft\":{\"name\":\"Draft\",\"text_color\":\"white\",\"background_color\":\"light-gray\",\"listing_subdued\":false,\"listing_badge\":true,\"soft_delete\":false},\"invited\":{\"name\":\"Invited\",\"text_color\":\"white\",\"background_color\":\"light-gray\",\"listing_subdued\":false,\"listing_badge\":true,\"soft_delete\":false},\"active\":{\"name\":\"Active\",\"text_color\":\"white\",\"background_color\":\"success\",\"listing_subdued\":false,\"listing_badge\":false,\"soft_delete\":false},\"suspended\":{\"name\":\"Suspended\",\"text_color\":\"white\",\"background_color\":\"light-gray\",\"listing_subdued\":false,\"listing_badge\":true,\"soft_delete\":false},\"deleted\":{\"name\":\"Deleted\",\"text_color\":\"white\",\"background_color\":\"danger\",\"listing_subdued\":false,\"listing_badge\":true,\"soft_delete\":true}}}',1,NULL,1,0,0,0,2,'full',NULL,NULL,NULL),(122,'directus_users','first_name','string','text-input','{\"placeholder\":\"Enter your give name...\"}',1,NULL,1,0,0,0,3,'half',NULL,NULL,NULL),(123,'directus_users','last_name','string','text-input','{\"placeholder\":\"Enter your surname...\"}',1,NULL,1,0,0,0,4,'half',NULL,NULL,NULL),(124,'directus_users','email','string','text-input','{\"placeholder\":\"Enter your email address...\"}',1,'$email',1,0,0,0,5,'half',NULL,NULL,NULL),(125,'directus_users','email_notifications','boolean','toggle',NULL,1,NULL,0,0,0,0,6,'half',NULL,NULL,NULL),(126,'directus_users','password','hash','password',NULL,1,NULL,1,0,0,0,7,'half',NULL,NULL,NULL),(127,'directus_users','roles','o2m','user-roles',NULL,1,NULL,1,0,0,0,8,'half',NULL,NULL,NULL),(128,'directus_users','company','string','text-input','{\"placeholder\":\"Enter your company or organization name...\"}',0,NULL,0,0,0,0,9,'half',NULL,NULL,NULL),(129,'directus_users','title','string','text-input','{\"placeholder\":\"Enter your title or role...\"}',0,NULL,0,0,0,0,10,'half',NULL,NULL,NULL),(130,'directus_users','timezone','string','dropdown','{\"choices\":{\"Pacific\\/Midway\":\"(UTC-11:00) Midway Island\",\"Pacific\\/Samoa\":\"(UTC-11:00) Samoa\",\"Pacific\\/Honolulu\":\"(UTC-10:00) Hawaii\",\"US\\/Alaska\":\"(UTC-09:00) Alaska\",\"America\\/Los_Angeles\":\"(UTC-08:00) Pacific Time (US & Canada)\",\"America\\/Tijuana\":\"(UTC-08:00) Tijuana\",\"US\\/Arizona\":\"(UTC-07:00) Arizona\",\"America\\/Chihuahua\":\"(UTC-07:00) Chihuahua\",\"America\\/Mexico\\/La_Paz\":\"(UTC-07:00) La Paz\",\"America\\/Mazatlan\":\"(UTC-07:00) Mazatlan\",\"US\\/Mountain\":\"(UTC-07:00) Mountain Time (US & Canada)\",\"America\\/Managua\":\"(UTC-06:00) Central America\",\"US\\/Central\":\"(UTC-06:00) Central Time (US & Canada)\",\"America\\/Guadalajara\":\"(UTC-06:00) Guadalajara\",\"America\\/Mexico_City\":\"(UTC-06:00) Mexico City\",\"America\\/Monterrey\":\"(UTC-06:00) Monterrey\",\"Canada\\/Saskatchewan\":\"(UTC-06:00) Saskatchewan\",\"America\\/Bogota\":\"(UTC-05:00) Bogota\",\"US\\/Eastern\":\"(UTC-05:00) Eastern Time (US & Canada)\",\"US\\/East-Indiana\":\"(UTC-05:00) Indiana (East)\",\"America\\/Lima\":\"(UTC-05:00) Lima\",\"America\\/Quito\":\"(UTC-05:00) Quito\",\"Canada\\/Atlantic\":\"(UTC-04:00) Atlantic Time (Canada)\",\"America\\/New_York\":\"(UTC-04:00) New York\",\"America\\/Caracas\":\"(UTC-04:30) Caracas\",\"America\\/La_Paz\":\"(UTC-04:00) La Paz\",\"America\\/Santiago\":\"(UTC-04:00) Santiago\",\"America\\/Santo_Domingo\":\"(UTC-04:00) Santo Domingo\",\"Canada\\/Newfoundland\":\"(UTC-03:30) Newfoundland\",\"America\\/Sao_Paulo\":\"(UTC-03:00) Brasilia\",\"America\\/Argentina\\/Buenos_Aires\":\"(UTC-03:00) Buenos Aires\",\"America\\/Argentina\\/GeorgeTown\":\"(UTC-03:00) Georgetown\",\"America\\/Godthab\":\"(UTC-03:00) Greenland\",\"America\\/Noronha\":\"(UTC-02:00) Mid-Atlantic\",\"Atlantic\\/Azores\":\"(UTC-01:00) Azores\",\"Atlantic\\/Cape_Verde\":\"(UTC-01:00) Cape Verde Is.\",\"Africa\\/Casablanca\":\"(UTC+00:00) Casablanca\",\"Europe\\/Edinburgh\":\"(UTC+00:00) Edinburgh\",\"Etc\\/Greenwich\":\"(UTC+00:00) Greenwich Mean Time : Dublin\",\"Europe\\/Lisbon\":\"(UTC+00:00) Lisbon\",\"Europe\\/London\":\"(UTC+00:00) London\",\"Africa\\/Monrovia\":\"(UTC+00:00) Monrovia\",\"UTC\":\"(UTC+00:00) UTC\",\"Europe\\/Amsterdam\":\"(UTC+01:00) Amsterdam\",\"Europe\\/Belgrade\":\"(UTC+01:00) Belgrade\",\"Europe\\/Berlin\":\"(UTC+01:00) Berlin\",\"Europe\\/Bern\":\"(UTC+01:00) Bern\",\"Europe\\/Bratislava\":\"(UTC+01:00) Bratislava\",\"Europe\\/Brussels\":\"(UTC+01:00) Brussels\",\"Europe\\/Budapest\":\"(UTC+01:00) Budapest\",\"Europe\\/Copenhagen\":\"(UTC+01:00) Copenhagen\",\"Europe\\/Ljubljana\":\"(UTC+01:00) Ljubljana\",\"Europe\\/Madrid\":\"(UTC+01:00) Madrid\",\"Europe\\/Paris\":\"(UTC+01:00) Paris\",\"Europe\\/Prague\":\"(UTC+01:00) Prague\",\"Europe\\/Rome\":\"(UTC+01:00) Rome\",\"Europe\\/Sarajevo\":\"(UTC+01:00) Sarajevo\",\"Europe\\/Skopje\":\"(UTC+01:00) Skopje\",\"Europe\\/Stockholm\":\"(UTC+01:00) Stockholm\",\"Europe\\/Vienna\":\"(UTC+01:00) Vienna\",\"Europe\\/Warsaw\":\"(UTC+01:00) Warsaw\",\"Africa\\/Lagos\":\"(UTC+01:00) West Central Africa\",\"Europe\\/Zagreb\":\"(UTC+01:00) Zagreb\",\"Europe\\/Athens\":\"(UTC+02:00) Athens\",\"Europe\\/Bucharest\":\"(UTC+02:00) Bucharest\",\"Africa\\/Cairo\":\"(UTC+02:00) Cairo\",\"Africa\\/Harare\":\"(UTC+02:00) Harare\",\"Europe\\/Helsinki\":\"(UTC+02:00) Helsinki\",\"Europe\\/Istanbul\":\"(UTC+02:00) Istanbul\",\"Asia\\/Jerusalem\":\"(UTC+02:00) Jerusalem\",\"Europe\\/Kyiv\":\"(UTC+02:00) Kyiv\",\"Africa\\/Johannesburg\":\"(UTC+02:00) Pretoria\",\"Europe\\/Riga\":\"(UTC+02:00) Riga\",\"Europe\\/Sofia\":\"(UTC+02:00) Sofia\",\"Europe\\/Tallinn\":\"(UTC+02:00) Tallinn\",\"Europe\\/Vilnius\":\"(UTC+02:00) Vilnius\",\"Asia\\/Baghdad\":\"(UTC+03:00) Baghdad\",\"Asia\\/Kuwait\":\"(UTC+03:00) Kuwait\",\"Europe\\/Minsk\":\"(UTC+03:00) Minsk\",\"Africa\\/Nairobi\":\"(UTC+03:00) Nairobi\",\"Asia\\/Riyadh\":\"(UTC+03:00) Riyadh\",\"Europe\\/Volgograd\":\"(UTC+03:00) Volgograd\",\"Asia\\/Tehran\":\"(UTC+03:30) Tehran\",\"Asia\\/Abu_Dhabi\":\"(UTC+04:00) Abu Dhabi\",\"Asia\\/Baku\":\"(UTC+04:00) Baku\",\"Europe\\/Moscow\":\"(UTC+04:00) Moscow\",\"Asia\\/Muscat\":\"(UTC+04:00) Muscat\",\"Europe\\/St_Petersburg\":\"(UTC+04:00) St. Petersburg\",\"Asia\\/Tbilisi\":\"(UTC+04:00) Tbilisi\",\"Asia\\/Yerevan\":\"(UTC+04:00) Yerevan\",\"Asia\\/Kabul\":\"(UTC+04:30) Kabul\",\"Asia\\/Islamabad\":\"(UTC+05:00) Islamabad\",\"Asia\\/Karachi\":\"(UTC+05:00) Karachi\",\"Asia\\/Tashkent\":\"(UTC+05:00) Tashkent\",\"Asia\\/Calcutta\":\"(UTC+05:30) Chennai\",\"Asia\\/Kolkata\":\"(UTC+05:30) Kolkata\",\"Asia\\/Mumbai\":\"(UTC+05:30) Mumbai\",\"Asia\\/New_Delhi\":\"(UTC+05:30) New Delhi\",\"Asia\\/Sri_Jayawardenepura\":\"(UTC+05:30) Sri Jayawardenepura\",\"Asia\\/Katmandu\":\"(UTC+05:45) Kathmandu\",\"Asia\\/Almaty\":\"(UTC+06:00) Almaty\",\"Asia\\/Astana\":\"(UTC+06:00) Astana\",\"Asia\\/Dhaka\":\"(UTC+06:00) Dhaka\",\"Asia\\/Yekaterinburg\":\"(UTC+06:00) Ekaterinburg\",\"Asia\\/Rangoon\":\"(UTC+06:30) Rangoon\",\"Asia\\/Bangkok\":\"(UTC+07:00) Bangkok\",\"Asia\\/Hanoi\":\"(UTC+07:00) Hanoi\",\"Asia\\/Jakarta\":\"(UTC+07:00) Jakarta\",\"Asia\\/Novosibirsk\":\"(UTC+07:00) Novosibirsk\",\"Asia\\/Beijing\":\"(UTC+08:00) Beijing\",\"Asia\\/Chongqing\":\"(UTC+08:00) Chongqing\",\"Asia\\/Hong_Kong\":\"(UTC+08:00) Hong Kong\",\"Asia\\/Krasnoyarsk\":\"(UTC+08:00) Krasnoyarsk\",\"Asia\\/Kuala_Lumpur\":\"(UTC+08:00) Kuala Lumpur\",\"Australia\\/Perth\":\"(UTC+08:00) Perth\",\"Asia\\/Singapore\":\"(UTC+08:00) Singapore\",\"Asia\\/Taipei\":\"(UTC+08:00) Taipei\",\"Asia\\/Ulan_Bator\":\"(UTC+08:00) Ulaan Bataar\",\"Asia\\/Urumqi\":\"(UTC+08:00) Urumqi\",\"Asia\\/Irkutsk\":\"(UTC+09:00) Irkutsk\",\"Asia\\/Osaka\":\"(UTC+09:00) Osaka\",\"Asia\\/Sapporo\":\"(UTC+09:00) Sapporo\",\"Asia\\/Seoul\":\"(UTC+09:00) Seoul\",\"Asia\\/Tokyo\":\"(UTC+09:00) Tokyo\",\"Australia\\/Adelaide\":\"(UTC+09:30) Adelaide\",\"Australia\\/Darwin\":\"(UTC+09:30) Darwin\",\"Australia\\/Brisbane\":\"(UTC+10:00) Brisbane\",\"Australia\\/Canberra\":\"(UTC+10:00) Canberra\",\"Pacific\\/Guam\":\"(UTC+10:00) Guam\",\"Australia\\/Hobart\":\"(UTC+10:00) Hobart\",\"Australia\\/Melbourne\":\"(UTC+10:00) Melbourne\",\"Pacific\\/Port_Moresby\":\"(UTC+10:00) Port Moresby\",\"Australia\\/Sydney\":\"(UTC+10:00) Sydney\",\"Asia\\/Yakutsk\":\"(UTC+10:00) Yakutsk\",\"Asia\\/Vladivostok\":\"(UTC+11:00) Vladivostok\",\"Pacific\\/Auckland\":\"(UTC+12:00) Auckland\",\"Pacific\\/Fiji\":\"(UTC+12:00) Fiji\",\"Pacific\\/Kwajalein\":\"(UTC+12:00) International Date Line West\",\"Asia\\/Kamchatka\":\"(UTC+12:00) Kamchatka\",\"Asia\\/Magadan\":\"(UTC+12:00) Magadan\",\"Pacific\\/Marshall_Is\":\"(UTC+12:00) Marshall Is.\",\"Asia\\/New_Caledonia\":\"(UTC+12:00) New Caledonia\",\"Asia\\/Solomon_Is\":\"(UTC+12:00) Solomon Is.\",\"Pacific\\/Wellington\":\"(UTC+12:00) Wellington\",\"Pacific\\/Tongatapu\":\"(UTC+13:00) Nuku\'alofa\"},\"placeholder\":\"Choose a timezone...\"}',1,NULL,1,0,0,0,11,'half',NULL,NULL,NULL),(131,'directus_users','locale','string','language','{\"limit\":true}',1,NULL,1,0,0,0,12,'half',NULL,NULL,NULL),(132,'directus_users','locale_options','json','json',NULL,1,NULL,0,0,1,1,13,'full',NULL,NULL,NULL),(133,'directus_users','token','string','text-input',NULL,1,NULL,0,0,1,1,14,'full',NULL,NULL,NULL),(134,'directus_users','last_login','datetime','datetime',NULL,1,NULL,0,1,0,0,15,'half',NULL,NULL,NULL),(135,'directus_users','last_access_on','datetime','datetime',NULL,1,NULL,0,1,1,0,16,'half',NULL,NULL,NULL),(136,'directus_users','last_page','string','text-input',NULL,1,NULL,0,1,1,1,17,'half',NULL,NULL,NULL),(137,'directus_users','avatar','file','file',NULL,1,NULL,0,0,0,0,18,'full',NULL,NULL,NULL),(138,'directus_users','invite_token','string','text-input',NULL,1,NULL,0,0,1,1,NULL,'full',NULL,NULL,NULL),(139,'directus_users','invite_accepted','boolean','toggle',NULL,1,NULL,0,0,1,1,NULL,'full',NULL,NULL,NULL),(140,'directus_users','last_ip','string','text-input',NULL,1,NULL,0,1,1,0,NULL,'full',NULL,NULL,NULL),(141,'directus_users','external_id','string','text-input',NULL,1,NULL,0,1,1,0,NULL,'full',NULL,NULL,NULL),(142,'directus_user_roles','id','integer','primary-key',NULL,1,NULL,1,0,1,0,NULL,'full',NULL,NULL,NULL),(143,'directus_user_roles','user','m2o','many-to-one',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL),(144,'directus_user_roles','role','m2o','many-to-one',NULL,1,NULL,0,0,0,0,NULL,'full',NULL,NULL,NULL); - -/*Table structure for table `directus_files` */ - -DROP TABLE IF EXISTS `directus_files`; +) ENGINE=InnoDB AUTO_INCREMENT=167 DEFAULT CHARSET=utf8; CREATE TABLE `directus_files` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `storage` varchar(50) NOT NULL DEFAULT 'local', - `filename` varchar(255) NOT NULL, + `private_hash` varchar(16) DEFAULT NULL, + `filename_disk` varchar(255) NOT NULL, + `filename_download` varchar(255) NOT NULL, `title` varchar(255) DEFAULT NULL, `type` varchar(255) DEFAULT NULL, `uploaded_by` int(11) unsigned NOT NULL, `uploaded_on` datetime NOT NULL, `charset` varchar(50) DEFAULT NULL, - `filesize` int(11) unsigned NOT NULL DEFAULT '0', + `filesize` int(11) unsigned NOT NULL DEFAULT 0, `width` int(11) unsigned DEFAULT NULL, `height` int(11) unsigned DEFAULT NULL, `duration` int(11) DEFAULT NULL, `embed` varchar(200) DEFAULT NULL, `folder` int(11) unsigned DEFAULT NULL, - `description` text, + `description` text DEFAULT NULL, `location` varchar(200) DEFAULT NULL, `tags` varchar(255) DEFAULT NULL, `checksum` varchar(32) DEFAULT NULL, - `metadata` text, + `metadata` text DEFAULT NULL, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -/*Data for the table `directus_files` */ - -/*Table structure for table `directus_folders` */ - -DROP TABLE IF EXISTS `directus_folders`; - CREATE TABLE `directus_folders` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(191) CHARACTER SET utf8mb4 NOT NULL, @@ -164,29 +117,15 @@ CREATE TABLE `directus_folders` ( UNIQUE KEY `idx_name_parent_folder` (`name`,`parent_folder`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -/*Data for the table `directus_folders` */ - -/*Table structure for table `directus_migrations` */ - -DROP TABLE IF EXISTS `directus_migrations`; - CREATE TABLE `directus_migrations` ( `version` bigint(20) NOT NULL, `migration_name` varchar(100) DEFAULT NULL, `start_time` timestamp NULL DEFAULT NULL, `end_time` timestamp NULL DEFAULT NULL, - `breakpoint` tinyint(1) NOT NULL DEFAULT '0', + `breakpoint` tinyint(1) NOT NULL DEFAULT 0, PRIMARY KEY (`version`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -/*Data for the table `directus_migrations` */ - -insert into `directus_migrations`(`version`,`migration_name`,`start_time`,`end_time`,`breakpoint`) values (20180220023138,'CreateActivityTable','2019-06-22 07:28:11','2019-06-22 07:28:11',0),(20180220023144,'CreateActivitySeenTable','2019-06-22 07:28:11','2019-06-22 07:28:11',0),(20180220023152,'CreateCollectionsPresetsTable','2019-06-22 07:28:11','2019-06-22 07:28:11',0),(20180220023157,'CreateCollectionsTable','2019-06-22 07:28:11','2019-06-22 07:28:11',0),(20180220023202,'CreateFieldsTable','2019-06-22 07:28:11','2019-06-22 07:28:11',0),(20180220023208,'CreateFilesTable','2019-06-22 07:28:11','2019-06-22 07:28:11',0),(20180220023213,'CreateFoldersTable','2019-06-22 07:28:11','2019-06-22 07:28:11',0),(20180220023217,'CreateRolesTable','2019-06-22 07:28:11','2019-06-22 07:28:11',0),(20180220023226,'CreatePermissionsTable','2019-06-22 07:28:11','2019-06-22 07:28:11',0),(20180220023232,'CreateRelationsTable','2019-06-22 07:28:11','2019-06-22 07:28:11',0),(20180220023238,'CreateRevisionsTable','2019-06-22 07:28:11','2019-06-22 07:28:11',0),(20180220023243,'CreateSettingsTable','2019-06-22 07:28:11','2019-06-22 07:28:11',0),(20180220023248,'CreateUsersTable','2019-06-22 07:28:11','2019-06-22 07:28:11',0),(20180426173310,'CreateUserRoles','2019-06-22 07:28:11','2019-06-22 07:28:12',0),(20181022175715,'Upgrade070003','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20181102153600,'TimezoneChoices','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20181105165224,'Upgrade070006','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20181122195602,'LocaleInterface','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20181123171520,'RemoveScope','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20181210204720,'AddTrustedProxiesSettingField','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20181222023800,'AddProjectUrlSettingField','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20181227042755,'IncreaseUsersLastPageLength','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20190104155309,'AddUsersEmailValidation','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20190111193724,'AddAppUrlSettingField','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20190111212736,'AddMissingSettingsField','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20190118181424,'AddRolesUsersField','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20190130215921,'AddFilesChecksumField','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20190318173400,'AddNavOverride','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20190412122400,'SetPasswordTypeToHash','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20190412123000,'UseFileInterface','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20190412145800,'SetO2MOptionsRoles','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20190415125300,'SetWidth','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20190419154400,'SettingsFields','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20190419161200,'CollectionNotes','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20190419173000,'MiscRequiredFields','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20190422131600,'UseJson','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20190426156200,'SetNullableValueFieldSettingsTable','2019-06-22 07:28:32','2019-06-22 07:28:32',0),(20190520094300,'UseTimeline','2019-06-22 07:28:32','2019-06-22 07:28:32',0); - -/*Table structure for table `directus_permissions` */ - -DROP TABLE IF EXISTS `directus_permissions`; - CREATE TABLE `directus_permissions` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `collection` varchar(64) NOT NULL, @@ -204,12 +143,6 @@ CREATE TABLE `directus_permissions` ( PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -/*Data for the table `directus_permissions` */ - -/*Table structure for table `directus_relations` */ - -DROP TABLE IF EXISTS `directus_relations`; - CREATE TABLE `directus_relations` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `collection_many` varchar(64) NOT NULL, @@ -218,15 +151,7 @@ CREATE TABLE `directus_relations` ( `field_one` varchar(64) DEFAULT NULL, `junction_field` varchar(64) DEFAULT NULL, PRIMARY KEY (`id`) -) ENGINE=InnoDB AUTO_INCREMENT=15 DEFAULT CHARSET=utf8; - -/*Data for the table `directus_relations` */ - -insert into `directus_relations`(`id`,`collection_many`,`field_many`,`collection_one`,`field_one`,`junction_field`) values (1,'directus_activity','action_by','directus_users',NULL,NULL),(2,'directus_activity_seen','user','directus_users',NULL,NULL),(3,'directus_activity_seen','activity','directus_activity',NULL,NULL),(4,'directus_collections_presets','user','directus_users',NULL,NULL),(5,'directus_collections_presets','group','directus_groups',NULL,NULL),(6,'directus_files','uploaded_by','directus_users',NULL,NULL),(7,'directus_files','folder','directus_folders',NULL,NULL),(8,'directus_folders','parent_folder','directus_folders',NULL,NULL),(9,'directus_permissions','group','directus_groups',NULL,NULL),(10,'directus_revisions','activity','directus_activity',NULL,NULL),(11,'directus_user_roles','user','directus_users','roles','role'),(12,'directus_user_roles','role','directus_roles','users','user'),(13,'directus_users','avatar','directus_files',NULL,NULL),(14,'directus_fields','collection','directus_collections','fields',NULL); - -/*Table structure for table `directus_revisions` */ - -DROP TABLE IF EXISTS `directus_revisions`; +) ENGINE=InnoDB AUTO_INCREMENT=12 DEFAULT CHARSET=utf8; CREATE TABLE `directus_revisions` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, @@ -234,101 +159,364 @@ CREATE TABLE `directus_revisions` ( `collection` varchar(64) NOT NULL, `item` varchar(255) NOT NULL, `data` longtext NOT NULL, - `delta` longtext, + `delta` longtext DEFAULT NULL, `parent_collection` varchar(64) DEFAULT NULL, `parent_item` varchar(255) DEFAULT NULL, - `parent_changed` tinyint(1) unsigned DEFAULT '0', + `parent_changed` tinyint(1) unsigned DEFAULT 0, PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; -/*Data for the table `directus_revisions` */ - -/*Table structure for table `directus_roles` */ - -DROP TABLE IF EXISTS `directus_roles`; - CREATE TABLE `directus_roles` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(100) NOT NULL, `description` varchar(500) DEFAULT NULL, - `ip_whitelist` text, - `nav_blacklist` text, + `ip_whitelist` text DEFAULT NULL, `external_id` varchar(255) DEFAULT NULL, - `nav_override` text, + `module_listing` text DEFAULT NULL, + `collection_listing` text DEFAULT NULL, + `enforce_2fa` tinyint(1) DEFAULT 0, PRIMARY KEY (`id`), UNIQUE KEY `idx_group_name` (`name`), UNIQUE KEY `idx_roles_external_id` (`external_id`) ) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8; -/*Data for the table `directus_roles` */ - -insert into `directus_roles`(`id`,`name`,`description`,`ip_whitelist`,`nav_blacklist`,`external_id`,`nav_override`) values (1,'Administrator','Admins have access to all managed data within the system by default',NULL,NULL,NULL,NULL),(2,'Public','This sets the data that is publicly available through the API without a token',NULL,NULL,NULL,NULL); - -/*Table structure for table `directus_settings` */ - -DROP TABLE IF EXISTS `directus_settings`; - CREATE TABLE `directus_settings` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `key` varchar(64) NOT NULL, - `value` text, + `value` text NOT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx_key` (`key`) -) ENGINE=InnoDB AUTO_INCREMENT=16 DEFAULT CHARSET=utf8; +) ENGINE=InnoDB AUTO_INCREMENT=20 DEFAULT CHARSET=utf8; -/*Data for the table `directus_settings` */ - -insert into `directus_settings`(`id`,`key`,`value`) values (1,'logo',''),(2,'color','darkest-gray'),(3,'default_limit','200'),(4,'sort_null_last','1'),(5,'auto_sign_out','60'),(6,'youtube_api_key',''),(7,'trusted_proxies',''),(8,'thumbnail_dimensions','200x200'),(9,'thumbnail_quality_tags','{\"poor\": 25, \"good\": 50, \"better\": 75, \"best\": 100}'),(10,'thumbnail_actions','{\"contain\":{\"options\":{\"resizeCanvas\":false,\"position\":\"center\",\"resizeRelative\":false,\"canvasBackground\":\"ccc\"}},\"crop\":{\"options\":{\"position\":\"center\"}}}'),(11,'thumbnail_cache_ttl','86400'),(12,'thumbnail_not_found_location',''),(13,'project_name','Directus'),(14,'app_url',''),(15,'project_url',''); - -/*Table structure for table `directus_user_roles` */ - -DROP TABLE IF EXISTS `directus_user_roles`; - -CREATE TABLE `directus_user_roles` ( +CREATE TABLE `directus_user_sessions` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `user` int(11) unsigned DEFAULT NULL, - `role` int(11) unsigned DEFAULT NULL, - PRIMARY KEY (`id`), - UNIQUE KEY `idx_user_role` (`user`,`role`) -) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; - -/*Data for the table `directus_user_roles` */ - -insert into `directus_user_roles`(`id`,`user`,`role`) values (1,1,1); - -/*Table structure for table `directus_users` */ - -DROP TABLE IF EXISTS `directus_users`; + `token_type` varchar(255) DEFAULT NULL, + `token` varchar(520) DEFAULT NULL, + `ip_address` varchar(255) DEFAULT NULL, + `user_agent` text DEFAULT NULL, + `created_on` datetime DEFAULT NULL, + `token_expired_at` datetime DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `directus_users` ( `id` int(11) unsigned NOT NULL AUTO_INCREMENT, `status` varchar(16) NOT NULL DEFAULT 'draft', + `role` int(11) DEFAULT NULL, `first_name` varchar(50) DEFAULT NULL, `last_name` varchar(50) DEFAULT NULL, `email` varchar(128) NOT NULL, `password` varchar(255) DEFAULT NULL, `token` varchar(255) DEFAULT NULL, - `timezone` varchar(32) NOT NULL DEFAULT 'UTC', - `locale` varchar(8) DEFAULT 'en-US', - `locale_options` text, + `timezone` varchar(32) NOT NULL DEFAULT 'America/New_York', + `locale` varchar(8) DEFAULT NULL, + `locale_options` text DEFAULT NULL, `avatar` int(11) unsigned DEFAULT NULL, `company` varchar(191) DEFAULT NULL, `title` varchar(191) DEFAULT NULL, - `email_notifications` int(1) NOT NULL DEFAULT '1', + `email_notifications` int(1) NOT NULL DEFAULT 1, `last_access_on` datetime DEFAULT NULL, `last_page` varchar(192) DEFAULT NULL, `external_id` varchar(255) DEFAULT NULL, + `theme` varchar(100) DEFAULT 'auto', + `2fa_secret` varchar(100) DEFAULT NULL, PRIMARY KEY (`id`), UNIQUE KEY `idx_users_email` (`email`), UNIQUE KEY `idx_users_token` (`token`), UNIQUE KEY `idx_users_external_id` (`external_id`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8; -/*Data for the table `directus_users` */ - -insert into `directus_users`(`id`,`status`,`first_name`,`last_name`,`email`,`password`,`token`,`timezone`,`locale`,`locale_options`,`avatar`,`company`,`title`,`email_notifications`,`last_access_on`,`last_page`,`external_id`) values (1,'active','Admin','User','admin@example.com','$2y$12$WzyHxXSOPzSKtDeOQek2P.mlHyYTslUUzZim9nG8aqUMS8ekhGI3m',NULL,'UTC','en-US',NULL,NULL,NULL,NULL,1,'2019-06-22 07:28:29','/settings',NULL); +CREATE TABLE `directus_webhooks` ( + `id` int(11) unsigned NOT NULL AUTO_INCREMENT, + `status` varchar(16) NOT NULL DEFAULT 'inactive', + `http_action` varchar(255) DEFAULT NULL, + `url` varchar(510) DEFAULT NULL, + `collection` varchar(255) DEFAULT NULL, + `directus_action` varchar(255) DEFAULT NULL, + PRIMARY KEY (`id`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; +INSERT INTO `directus_collection_presets` (`id`, `title`, `user`, `role`, `collection`, `search_query`, `filters`, `view_type`, `view_query`, `view_options`, `translation`) VALUES ('1', NULL, NULL, NULL, 'directus_activity', NULL, NULL, 'timeline', '{\"timeline\":{\"sort\":\"-action_on\"}}', '{\"timeline\":{\"date\":\"action_on\",\"title\":\"{{ action }} by {{ action_by.first_name }} {{ action_by.last_name }} (#{{ item }})\",\"content\":\"collection\",\"color\":\"action\"}}', NULL), +('2', NULL, NULL, NULL, 'directus_files', NULL, NULL, 'cards', NULL, '{\"cards\":{\"title\":\"title\",\"subtitle\":\"type\",\"content\":\"description\",\"src\":\"data\"}}', NULL), +('3', NULL, NULL, NULL, 'directus_users', NULL, NULL, 'cards', NULL, '{\"cards\":{\"title\":\"first_name\",\"subtitle\":\"last_name\",\"content\":\"title\",\"src\":\"avatar\",\"icon\":\"person\"}}', NULL), +('4', NULL, NULL, NULL, 'directus_webhooks', NULL, NULL, 'tabular', '{\"tabular\":{\"fields\":\"status,http_action,url,collection,directus_action\"}}', '{\"tabular\":{\"widths\":{\"status\":32,\"http_action\":72,\"url\":200,\"collection\":200,\"directus_action\":200}}}', NULL); + +INSERT INTO `directus_fields` (`id`, `collection`, `field`, `type`, `interface`, `options`, `locked`, `validation`, `required`, `readonly`, `hidden_detail`, `hidden_browse`, `sort`, `width`, `group`, `note`, `translation`) VALUES ('1', 'directus_fields', 'id', 'integer', 'primary-key', NULL, '1', NULL, '1', '0', '1', '0', NULL, 'full', NULL, NULL, NULL), +('2', 'directus_fields', 'collection', 'm2o', 'many-to-one', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('3', 'directus_fields', 'field', 'string', 'text-input', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('4', 'directus_fields', 'type', 'string', 'primary-key', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('5', 'directus_fields', 'interface', 'string', 'primary-key', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('6', 'directus_fields', 'options', 'json', 'json', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('7', 'directus_fields', 'locked', 'boolean', 'toggle', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('8', 'directus_fields', 'translation', 'json', 'repeater', '{\n \"fields\": [\n {\n \"field\": \"locale\",\n \"type\": \"string\",\n \"interface\": \"language\",\n \"options\": {\n \"limit\": true\n },\n \"width\": \"half\"\n },\n {\n \"field\": \"translation\",\n \"type\": \"string\",\n \"interface\": \"text-input\",\n \"width\": \"half\"\n }\n ]\n }', '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('9', 'directus_fields', 'readonly', 'boolean', 'toggle', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('10', 'directus_fields', 'validation', 'string', 'text-input', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('11', 'directus_fields', 'required', 'boolean', 'toggle', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('12', 'directus_fields', 'sort', 'sort', 'sort', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('13', 'directus_fields', 'note', 'string', 'text-input', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('14', 'directus_fields', 'hidden_detail', 'boolean', 'toggle', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('15', 'directus_fields', 'hidden_browse', 'boolean', 'toggle', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('16', 'directus_fields', 'width', 'integer', 'numeric', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('17', 'directus_fields', 'group', 'm2o', 'many-to-one', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('18', 'directus_activity', 'id', 'integer', 'primary-key', NULL, '1', NULL, '1', '1', '1', '0', NULL, 'full', NULL, NULL, NULL), +('19', 'directus_activity', 'action', 'string', 'text-input', '{\"iconRight\":\"change_history\"}', '1', NULL, '0', '1', '0', '0', '1', 'full', NULL, NULL, NULL), +('20', 'directus_activity', 'collection', 'string', 'collections', '{\"iconRight\":\"list_alt\",\"include_system\":true}', '1', NULL, '0', '1', '0', '0', '2', 'half', NULL, NULL, NULL), +('21', 'directus_activity', 'item', 'string', 'text-input', '{\"iconRight\":\"link\"}', '1', NULL, '0', '1', '0', '0', '3', 'half', NULL, NULL, NULL), +('22', 'directus_activity', 'action_by', 'integer', 'user', '{\"iconRight\":\"account_circle\"}', '1', NULL, '0', '1', '0', '0', '4', 'half', NULL, NULL, NULL), +('23', 'directus_activity', 'action_on', 'datetime', 'datetime', '{\"showRelative\":true,\"iconRight\":\"calendar_today\"}', '1', NULL, '0', '1', '0', '0', '5', 'half', NULL, NULL, NULL), +('24', 'directus_activity', 'edited_on', 'datetime', 'datetime', '{\"showRelative\":true,\"iconRight\":\"edit\"}', '1', NULL, '0', '1', '0', '0', '6', 'half', NULL, NULL, NULL), +('25', 'directus_activity', 'comment_deleted_on', 'datetime', 'datetime', '{\"showRelative\":true,\"iconRight\":\"delete_outline\"}', '1', NULL, '0', '1', '0', '0', '7', 'half', NULL, NULL, NULL), +('26', 'directus_activity', 'ip', 'string', 'text-input', '{\"iconRight\":\"my_location\"}', '1', NULL, '0', '1', '0', '0', '8', 'half', NULL, NULL, NULL), +('27', 'directus_activity', 'user_agent', 'string', 'text-input', '{\"iconRight\":\"devices_other\"}', '1', NULL, '0', '1', '0', '0', '9', 'half', NULL, NULL, NULL), +('28', 'directus_activity', 'comment', 'string', 'textarea', NULL, '1', NULL, '0', '1', '0', '0', '10', 'full', NULL, NULL, NULL), +('29', 'directus_collection_presets', 'id', 'integer', 'primary-key', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('30', 'directus_collection_presets', 'title', 'string', 'text-input', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('31', 'directus_collection_presets', 'user', 'integer', 'user', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('32', 'directus_collection_presets', 'role', 'm2o', 'many-to-one', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('33', 'directus_collection_presets', 'collection', 'm2o', 'many-to-one', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('34', 'directus_collection_presets', 'search_query', 'string', 'text-input', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('35', 'directus_collection_presets', 'filters', 'json', 'json', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('36', 'directus_collection_presets', 'view_options', 'json', 'json', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('37', 'directus_collection_presets', 'view_type', 'string', 'text-input', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('38', 'directus_collection_presets', 'view_query', 'json', 'json', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('39', 'directus_collections', 'fields', 'o2m', 'one-to-many', NULL, '1', NULL, '0', '0', '1', '1', '1', 'full', NULL, NULL, NULL), +('40', 'directus_collections', 'collection', 'string', 'primary-key', NULL, '1', NULL, '1', '1', '0', '0', '2', 'half', NULL, NULL, NULL), +('41', 'directus_collections', 'note', 'string', 'text-input', NULL, '1', NULL, '0', '0', '0', '0', '3', 'half', NULL, 'An internal description.', NULL), +('42', 'directus_collections', 'managed', 'boolean', 'toggle', NULL, '1', NULL, '0', '0', '1', '0', '4', 'half', NULL, '[Learn More](https://docs.directus.io/guides/collections.html#managing-collections).', NULL), +('43', 'directus_collections', 'hidden', 'boolean', 'toggle', NULL, '1', NULL, '0', '0', '0', '0', '5', 'half', NULL, '[Learn More](https://docs.directus.io/guides/collections.html#hidden).', NULL), +('44', 'directus_collections', 'single', 'boolean', 'toggle', NULL, '1', NULL, '0', '0', '0', '0', '6', 'half', NULL, '[Learn More](https://docs.directus.io/guides/collections.html#single).', NULL), +('45', 'directus_collections', 'translation', 'json', 'repeater', '{\n \"fields\": [\n {\n \"field\": \"locale\",\n \"type\": \"string\",\n \"interface\": \"language\",\n \"options\": {\n \"limit\": true\n },\n \"width\": \"half\"\n },\n {\n \"field\": \"translation\",\n \"type\": \"string\",\n \"interface\": \"text-input\",\n \"width\": \"half\"\n }\n ]\n }', '1', NULL, '0', '0', '0', '0', '7', 'full', NULL, NULL, NULL), +('46', 'directus_collections', 'icon', 'string', 'icon', NULL, '1', NULL, '0', '0', '0', '0', '8', 'full', NULL, 'The icon shown in the App\'s navigation sidebar.', NULL), +('47', 'directus_files', 'preview', 'alias', 'file-preview', NULL, '1', NULL, '0', '0', '0', '0', '1', 'full', NULL, NULL, NULL), +('48', 'directus_files', 'title', 'string', 'text-input', '{\"placeholder\":\"Enter a descriptive title...\",\"iconRight\":\"title\"}', '1', NULL, '0', '0', '0', '0', '2', 'full', NULL, NULL, NULL), +('49', 'directus_files', 'tags', 'array', 'tags', '{\"placeholder\":\"Enter a keyword then hit enter...\"}', '1', NULL, '0', '0', '0', '0', '3', 'half', NULL, NULL, NULL), +('50', 'directus_files', 'location', 'string', 'text-input', '{\"placeholder\":\"Enter a location...\",\"iconRight\":\"place\"}', '1', NULL, '0', '0', '0', '0', '4', 'half', NULL, NULL, NULL), +('51', 'directus_files', 'description', 'string', 'wysiwyg', '{\"toolbar\":[\"bold\",\"italic\",\"underline\",\"link\",\"code\"]}', '1', NULL, '0', '0', '0', '0', '5', 'full', NULL, NULL, NULL), +('52', 'directus_files', 'filename_download', 'string', 'text-input', '{\"monospace\":true,\"iconRight\":\"get_app\"}', '1', NULL, '0', '0', '0', '0', '6', 'full', NULL, NULL, NULL), +('53', 'directus_files', 'filename_disk', 'string', 'text-input', '{\"placeholder\":\"Enter a unique file name...\",\"iconRight\":\"insert_drive_file\"}', '1', NULL, '0', '0', '0', '0', '7', 'full', NULL, NULL, NULL), +('54', 'directus_files', 'private_hash', 'string', 'slug', '{\"iconRight\":\"lock\"}', '1', NULL, '0', '0', '0', '0', '8', 'half', NULL, NULL, NULL), +('55', 'directus_files', 'checksum', 'string', 'text-input', '{\"iconRight\":\"check\",\"monospace\":true}', '1', NULL, '0', '1', '0', '0', '9', 'half', NULL, NULL, NULL), +('56', 'directus_files', 'uploaded_on', 'datetime', 'datetime', '{\"iconRight\":\"today\"}', '1', NULL, '1', '1', '0', '0', '10', 'half', NULL, NULL, NULL), +('57', 'directus_files', 'uploaded_by', 'user_created', 'user-created', NULL, '1', NULL, '1', '1', '0', '0', '11', 'half', NULL, NULL, NULL), +('58', 'directus_files', 'width', 'integer', 'numeric', '{\"iconRight\":\"straighten\"}', '1', NULL, '0', '1', '0', '0', '12', 'half', NULL, NULL, NULL), +('59', 'directus_files', 'height', 'integer', 'numeric', '{\"iconRight\":\"straighten\"}', '1', NULL, '0', '1', '0', '0', '13', 'half', NULL, NULL, NULL), +('60', 'directus_files', 'duration', 'integer', 'numeric', '{\"iconRight\":\"timer\"}', '1', NULL, '0', '1', '0', '0', '14', 'half', NULL, NULL, NULL), +('61', 'directus_files', 'filesize', 'integer', 'file-size', '{\"iconRight\":\"storage\"}', '1', NULL, '0', '1', '0', '0', '15', 'half', NULL, NULL, NULL), +('62', 'directus_files', 'metadata', 'json', 'key-value', '{\"keyInterface\":\"text-input\",\"keyDataType\":\"string\",\"keyOptions\":{\"monospace\":true,\"placeholder\":\"Key\"},\"valueInterface\":\"text-input\",\"valueDataType\":\"string\",\"valueOptions\":{\"monospace\":true,\"placeholder\":\"Value\"}}', '1', NULL, '0', '0', '0', '0', '15', 'full', NULL, NULL, NULL), +('63', 'directus_files', 'data', 'alias', 'file', NULL, '1', NULL, '0', '0', '1', '0', NULL, 'full', NULL, NULL, NULL), +('64', 'directus_files', 'id', 'integer', 'primary-key', NULL, '1', NULL, '1', '0', '1', '0', NULL, 'full', NULL, NULL, NULL), +('65', 'directus_files', 'type', 'string', 'text-input', NULL, '1', NULL, '0', '1', '1', '0', NULL, 'full', NULL, NULL, NULL), +('66', 'directus_files', 'charset', 'string', 'text-input', NULL, '1', NULL, '0', '1', '1', '1', NULL, 'full', NULL, NULL, NULL), +('67', 'directus_files', 'embed', 'string', 'text-input', NULL, '1', NULL, '0', '1', '1', '0', NULL, 'full', NULL, NULL, NULL), +('68', 'directus_files', 'folder', 'm2o', 'many-to-one', NULL, '1', NULL, '0', '0', '1', '0', NULL, 'full', NULL, NULL, NULL), +('69', 'directus_files', 'storage', 'string', 'text-input', NULL, '1', NULL, '0', '0', '1', '1', NULL, 'full', NULL, NULL, NULL), +('70', 'directus_folders', 'id', 'integer', 'primary-key', NULL, '1', NULL, '1', '0', '1', '0', NULL, 'full', NULL, NULL, NULL), +('71', 'directus_folders', 'name', 'string', 'text-input', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('72', 'directus_folders', 'parent_folder', 'm2o', 'many-to-one', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('73', 'directus_roles', 'id', 'integer', 'primary-key', NULL, '1', NULL, '1', '0', '1', '0', NULL, 'full', NULL, NULL, NULL), +('74', 'directus_roles', 'external_id', 'string', 'text-input', NULL, '1', NULL, '0', '1', '1', '1', NULL, 'full', NULL, NULL, NULL), +('75', 'directus_roles', 'name', 'string', 'text-input', NULL, '1', NULL, '1', '0', '0', '0', '1', 'half', NULL, NULL, NULL), +('76', 'directus_roles', 'description', 'string', 'text-input', NULL, '1', NULL, '0', '0', '0', '0', '2', 'half', NULL, NULL, NULL), +('77', 'directus_roles', 'ip_whitelist', 'array', 'tags', '{\"\":\"Add an IP address...\"}', '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('78', 'directus_roles', 'enforce_2fa', 'boolean', 'toggle', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('79', 'directus_roles', 'users', 'o2m', 'one-to-many', '{\"fields\":\"first_name,last_name\"}', '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('80', 'directus_roles', 'module_listing', 'json', 'repeater', '{\n \"fields\": [\n {\n \"field\": \"name\",\n \"interface\": \"text-input\",\n \"type\": \"string\",\n \"width\": \"half\"\n },\n {\n \"field\": \"link\",\n \"interface\": \"text-input\",\n \"type\": \"string\",\n \"width\": \"half\"\n },\n {\n \"field\": \"icon\",\n \"interface\": \"icon\",\n \"type\": \"string\",\n \"width\": \"full\"\n }\n ]\n }', '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('81', 'directus_roles', 'collection_listing', 'json', 'repeater', '{\n \"fields\": [\n {\n \"field\": \"groups\",\n \"width\": \"full\",\n \"interface\": \"repeater\",\n \"type\": \"JSON\",\n \"options\": {\n \"template\": \"{{ label }}\",\n \"fields\": [\n {\n \"field\": \"label\",\n \"interface\": \"text-input\",\n \"type\": \"string\"\n },\n {\n \"field\": \"value\",\n \"interface\": \"text-input\",\n \"type\": \"string\"\n },\n {\n \"field\": \"icon\",\n \"width\": \"full\",\n \"interface\": \"icon\",\n \"type\": \"string\"\n }\n ]\n }\n }\n ]\n }', '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('82', 'directus_permissions', 'id', 'integer', 'primary-key', NULL, '1', NULL, '1', '0', '1', '0', NULL, 'full', NULL, NULL, NULL), +('83', 'directus_permissions', 'collection', 'm2o', 'many-to-one', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('84', 'directus_permissions', 'role', 'm2o', 'many-to-one', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('85', 'directus_permissions', 'status', 'string', 'text-input', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('86', 'directus_permissions', 'create', 'string', 'text-input', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('87', 'directus_permissions', 'read', 'string', 'text-input', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('88', 'directus_permissions', 'update', 'string', 'text-input', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('89', 'directus_permissions', 'delete', 'string', 'primary-key', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('90', 'directus_permissions', 'comment', 'string', 'text-input', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('91', 'directus_permissions', 'explain', 'string', 'text-input', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('92', 'directus_permissions', 'status_blacklist', 'array', 'tags', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('93', 'directus_permissions', 'read_field_blacklist', 'array', 'tags', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('94', 'directus_permissions', 'write_field_blacklist', 'array', 'tags', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('95', 'directus_relations', 'id', 'integer', 'primary-key', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('96', 'directus_relations', 'collection_many', 'string', 'collections', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('97', 'directus_relations', 'field_many', 'string', 'text-input', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('98', 'directus_relations', 'collection_one', 'string', 'collections', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('99', 'directus_relations', 'field_one', 'string', 'text-input', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('100', 'directus_relations', 'junction_field', 'string', 'text-input', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('101', 'directus_revisions', 'id', 'integer', 'primary-key', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('102', 'directus_revisions', 'activity', 'm2o', 'many-to-one', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('103', 'directus_revisions', 'collection', 'm2o', 'many-to-one', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('104', 'directus_revisions', 'item', 'string', 'text-input', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('105', 'directus_revisions', 'data', 'json', 'json', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('106', 'directus_revisions', 'delta', 'json', 'json', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('107', 'directus_revisions', 'parent_item', 'string', 'text-input', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('108', 'directus_revisions', 'parent_collection', 'string', 'collections', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('109', 'directus_revisions', 'parent_changed', 'boolean', 'toggle', NULL, '1', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('110', 'directus_settings', 'project_name', 'string', 'text-input', '{\"iconRight\":\"title\"}', '1', NULL, '1', '0', '0', '0', '1', 'half', NULL, 'Logo in the top-left of the App (40x40)', NULL), +('111', 'directus_settings', 'project_url', 'string', 'text-input', '{\"iconRight\":\"link\"}', '1', NULL, '0', '0', '0', '0', '2', 'half', NULL, 'External link for the App\'s top-left logo', NULL), +('112', 'directus_settings', 'project_logo', 'file', 'file', NULL, '1', NULL, '0', '0', '0', '0', '3', 'half', NULL, 'A 40x40 brand logo, ideally a white SVG/PNG', NULL), +('113', 'directus_settings', 'project_color', 'string', 'color', NULL, '1', NULL, '0', '0', '0', '0', '4', 'half', NULL, 'Color for login background and App\'s logo', NULL), +('114', 'directus_settings', 'project_foreground', 'file', 'file', NULL, '1', NULL, '0', '0', '0', '0', '5', 'half', NULL, 'Centered image (eg: logo) for the login page', NULL), +('115', 'directus_settings', 'project_background', 'file', 'file', NULL, '1', NULL, '0', '0', '0', '0', '6', 'half', NULL, 'Full-screen background for the login page', NULL), +('116', 'directus_settings', 'default_locale', 'string', 'language', '{\"limit\":true}', '1', NULL, '0', '0', '0', '0', '7', 'half', NULL, 'Default locale for Directus Users', NULL), +('117', 'directus_settings', 'telemetry', 'boolean', 'toggle', NULL, '1', NULL, '0', '0', '0', '0', '8', 'half', NULL, 'Learn More', NULL), +('118', 'directus_settings', 'data_divider', 'alias', 'divider', '{\"style\":\"large\",\"title\":\"Data\",\"hr\":true}', '1', NULL, '0', '0', '0', '1', '10', 'full', NULL, NULL, NULL), +('119', 'directus_settings', 'default_limit', 'integer', 'numeric', '{\"iconRight\":\"keyboard_tab\"}', '1', NULL, '1', '0', '0', '0', '11', 'half', NULL, 'Default item count in API and App responses', NULL), +('120', 'directus_settings', 'sort_null_last', 'boolean', 'toggle', NULL, '1', NULL, '0', '0', '0', '0', '12', 'half', NULL, 'NULL values are sorted last', NULL), +('121', 'directus_settings', 'security_divider', 'alias', 'divider', '{\"style\":\"large\",\"title\":\"Security\",\"hr\":true}', '1', NULL, '0', '0', '0', '1', '20', 'full', NULL, NULL, NULL), +('122', 'directus_settings', 'auto_sign_out', 'integer', 'numeric', '{\"iconRight\":\"timer\"}', '1', NULL, '1', '0', '0', '0', '22', 'half', NULL, 'Minutes before idle users are signed out', NULL), +('123', 'directus_settings', 'login_attempts_allowed', 'integer', 'numeric', '{\"iconRight\":\"lock\"}', '1', NULL, '0', '0', '0', '0', '23', 'half', NULL, 'Failed login attempts before suspending users', NULL), +('124', 'directus_settings', 'password_policy', 'string', 'dropdown', '{\"choices\":{\"\":\"None\",\"\\/^.{8,}$\\/\":\"Weak\",\"\\/(?=^.{8,}$)(?=.*\\\\d)(?=.*[a-z])(?=.*[A-Z])(?=.*[!@#$%^&*()_+}{\';\'?>.<,])(?!.*\\\\s).*$\\/\":\"Strong\"}}', '1', NULL, '0', '0', '0', '0', '24', 'half', NULL, 'Weak: Minimum length 8; Strong: 1 small-case letter, 1 capital letter, 1 digit, 1 special character and the length should be minimum 8', NULL), +('125', 'directus_settings', 'files_divider', 'alias', 'divider', '{\"style\":\"large\",\"title\":\"Files & Thumbnails\",\"hr\":true}', '1', NULL, '0', '0', '0', '1', '30', 'full', NULL, NULL, NULL), +('126', 'directus_settings', 'file_naming', 'string', 'dropdown', '{\"choices\":{\"uuid\":\"UUID (Obfuscated)\",\"file_name\":\"File Name (Readable)\"}}', '1', NULL, '0', '0', '0', '0', '31', 'half', NULL, 'File-system naming convention for uploads', NULL), +('127', 'directus_settings', 'file_max_size', 'string', 'text-input', '{\"placeholder\":\"eg: 4MB\",\"iconRight\":\"storage\"}', '1', NULL, '0', '0', '0', '0', '32', 'half', NULL, NULL, NULL), +('128', 'directus_settings', 'file_mimetype_whitelist', 'array', 'tags', '{\"placeholder\":\"Enter a file mimetype then hit enter (eg: image\\/jpeg)\"}', '1', NULL, '0', '0', '0', '0', '33', 'full', NULL, NULL, NULL), +('129', 'directus_settings', 'asset_whitelist', 'json', 'repeater', '{\"template\":\"{{key}}\",\"fields\":[{\"field\":\"key\",\"interface\":\"slug\",\"width\":\"half\",\"type\":\"string\",\"required\":true},{\"field\":\"fit\",\"interface\":\"dropdown\",\"width\":\"half\",\"type\":\"string\",\"options\":{\"choices\":{\"crop\":\"Crop (forces exact size)\",\"contain\":\"Contain (preserve aspect ratio)\"}},\"required\":true},{\"field\":\"width\",\"interface\":\"numeric\",\"width\":\"half\",\"type\":\"integer\",\"required\":true},{\"field\":\"height\",\"interface\":\"numeric\",\"width\":\"half\",\"type\":\"integer\",\"required\":true},{\"field\":\"quality\",\"interface\":\"slider\",\"width\":\"full\",\"type\":\"integer\",\"default\":80,\"options\":{\"min\":0,\"max\":100,\"step\":1},\"required\":true}]}', '0', NULL, '0', '0', '0', '0', '34', 'full', NULL, 'Defines how the thumbnail will be generated based on the requested params.', NULL), +('130', 'directus_settings', 'asset_whitelist_system', 'json', 'json', NULL, '0', NULL, '0', '1', '1', '1', '35', 'half', NULL, NULL, NULL), +('131', 'directus_settings', 'youtube_api_key', 'string', 'text-input', '{\"iconRight\":\"videocam\"}', '1', NULL, '0', '0', '0', '0', '36', 'full', NULL, 'Allows fetching more YouTube Embed info', NULL), +('132', 'directus_users', 'id', 'integer', 'primary-key', NULL, '1', NULL, '1', '0', '1', '0', '1', 'full', NULL, NULL, NULL), +('133', 'directus_users', 'status', 'status', 'status', '{\"status_mapping\":{\"draft\":{\"name\":\"Draft\",\"text_color\":\"white\",\"background_color\":\"light-gray\",\"listing_subdued\":false,\"listing_badge\":true,\"soft_delete\":false},\"invited\":{\"name\":\"Invited\",\"text_color\":\"white\",\"background_color\":\"light-gray\",\"listing_subdued\":false,\"listing_badge\":true,\"soft_delete\":false},\"active\":{\"name\":\"Active\",\"text_color\":\"white\",\"background_color\":\"success\",\"listing_subdued\":false,\"listing_badge\":false,\"soft_delete\":false},\"suspended\":{\"name\":\"Suspended\",\"text_color\":\"white\",\"background_color\":\"light-gray\",\"listing_subdued\":false,\"listing_badge\":true,\"soft_delete\":false},\"deleted\":{\"name\":\"Deleted\",\"text_color\":\"white\",\"background_color\":\"danger\",\"listing_subdued\":false,\"listing_badge\":true,\"soft_delete\":true}}}', '1', NULL, '1', '0', '0', '0', '2', 'full', NULL, NULL, NULL), +('134', 'directus_users', 'first_name', 'string', 'text-input', '{\"iconRight\":\"account_circle\"}', '1', NULL, '1', '0', '0', '0', '3', 'half', NULL, NULL, NULL), +('135', 'directus_users', 'last_name', 'string', 'text-input', '{\"iconRight\":\"account_circle\"}', '1', NULL, '1', '0', '0', '0', '4', 'half', NULL, NULL, NULL), +('136', 'directus_users', 'email', 'string', 'text-input', '{\"iconRight\":\"alternate_email\"}', '1', '$email', '1', '0', '0', '0', '5', 'half', NULL, NULL, NULL), +('137', 'directus_users', 'email_notifications', 'boolean', 'toggle', NULL, '1', NULL, '0', '0', '0', '0', '6', 'half', NULL, NULL, NULL), +('138', 'directus_users', 'password', 'hash', 'password', NULL, '1', NULL, '1', '0', '0', '0', '7', 'half', NULL, NULL, NULL), +('139', 'directus_users', 'role', 'm2o', 'user-roles', NULL, '1', NULL, '1', '0', '0', '0', '8', 'half', NULL, NULL, NULL), +('140', 'directus_users', 'company', 'string', 'text-input', '{\"iconRight\":\"location_city\"}', '0', NULL, '0', '0', '0', '0', '9', 'half', NULL, NULL, NULL), +('141', 'directus_users', 'title', 'string', 'text-input', '{\"iconRight\":\"text_fields\"}', '0', NULL, '0', '0', '0', '0', '10', 'half', NULL, NULL, NULL), +('142', 'directus_users', 'timezone', 'string', 'dropdown', '{\"choices\":{\"Pacific\\/Midway\":\"(UTC-11:00) Midway Island\",\"Pacific\\/Samoa\":\"(UTC-11:00) Samoa\",\"Pacific\\/Honolulu\":\"(UTC-10:00) Hawaii\",\"US\\/Alaska\":\"(UTC-09:00) Alaska\",\"America\\/Los_Angeles\":\"(UTC-08:00) Pacific Time (US & Canada)\",\"America\\/Tijuana\":\"(UTC-08:00) Tijuana\",\"US\\/Arizona\":\"(UTC-07:00) Arizona\",\"America\\/Chihuahua\":\"(UTC-07:00) Chihuahua\",\"America\\/Mexico\\/La_Paz\":\"(UTC-07:00) La Paz\",\"America\\/Mazatlan\":\"(UTC-07:00) Mazatlan\",\"US\\/Mountain\":\"(UTC-07:00) Mountain Time (US & Canada)\",\"America\\/Managua\":\"(UTC-06:00) Central America\",\"US\\/Central\":\"(UTC-06:00) Central Time (US & Canada)\",\"America\\/Guadalajara\":\"(UTC-06:00) Guadalajara\",\"America\\/Mexico_City\":\"(UTC-06:00) Mexico City\",\"America\\/Monterrey\":\"(UTC-06:00) Monterrey\",\"Canada\\/Saskatchewan\":\"(UTC-06:00) Saskatchewan\",\"America\\/Bogota\":\"(UTC-05:00) Bogota\",\"US\\/Eastern\":\"(UTC-05:00) Eastern Time (US & Canada)\",\"US\\/East-Indiana\":\"(UTC-05:00) Indiana (East)\",\"America\\/Lima\":\"(UTC-05:00) Lima\",\"America\\/Quito\":\"(UTC-05:00) Quito\",\"Canada\\/Atlantic\":\"(UTC-04:00) Atlantic Time (Canada)\",\"America\\/New_York\":\"(UTC-04:00) New York\",\"America\\/Caracas\":\"(UTC-04:30) Caracas\",\"America\\/La_Paz\":\"(UTC-04:00) La Paz\",\"America\\/Santiago\":\"(UTC-04:00) Santiago\",\"America\\/Santo_Domingo\":\"(UTC-04:00) Santo Domingo\",\"Canada\\/Newfoundland\":\"(UTC-03:30) Newfoundland\",\"America\\/Sao_Paulo\":\"(UTC-03:00) Brasilia\",\"America\\/Argentina\\/Buenos_Aires\":\"(UTC-03:00) Buenos Aires\",\"America\\/Argentina\\/GeorgeTown\":\"(UTC-03:00) Georgetown\",\"America\\/Godthab\":\"(UTC-03:00) Greenland\",\"America\\/Noronha\":\"(UTC-02:00) Mid-Atlantic\",\"Atlantic\\/Azores\":\"(UTC-01:00) Azores\",\"Atlantic\\/Cape_Verde\":\"(UTC-01:00) Cape Verde Is.\",\"Africa\\/Casablanca\":\"(UTC+00:00) Casablanca\",\"Europe\\/Edinburgh\":\"(UTC+00:00) Edinburgh\",\"Etc\\/Greenwich\":\"(UTC+00:00) Greenwich Mean Time : Dublin\",\"Europe\\/Lisbon\":\"(UTC+00:00) Lisbon\",\"Europe\\/London\":\"(UTC+00:00) London\",\"Africa\\/Monrovia\":\"(UTC+00:00) Monrovia\",\"UTC\":\"(UTC+00:00) UTC\",\"Europe\\/Amsterdam\":\"(UTC+01:00) Amsterdam\",\"Europe\\/Belgrade\":\"(UTC+01:00) Belgrade\",\"Europe\\/Berlin\":\"(UTC+01:00) Berlin\",\"Europe\\/Bern\":\"(UTC+01:00) Bern\",\"Europe\\/Bratislava\":\"(UTC+01:00) Bratislava\",\"Europe\\/Brussels\":\"(UTC+01:00) Brussels\",\"Europe\\/Budapest\":\"(UTC+01:00) Budapest\",\"Europe\\/Copenhagen\":\"(UTC+01:00) Copenhagen\",\"Europe\\/Ljubljana\":\"(UTC+01:00) Ljubljana\",\"Europe\\/Madrid\":\"(UTC+01:00) Madrid\",\"Europe\\/Paris\":\"(UTC+01:00) Paris\",\"Europe\\/Prague\":\"(UTC+01:00) Prague\",\"Europe\\/Rome\":\"(UTC+01:00) Rome\",\"Europe\\/Sarajevo\":\"(UTC+01:00) Sarajevo\",\"Europe\\/Skopje\":\"(UTC+01:00) Skopje\",\"Europe\\/Stockholm\":\"(UTC+01:00) Stockholm\",\"Europe\\/Vienna\":\"(UTC+01:00) Vienna\",\"Europe\\/Warsaw\":\"(UTC+01:00) Warsaw\",\"Africa\\/Lagos\":\"(UTC+01:00) West Central Africa\",\"Europe\\/Zagreb\":\"(UTC+01:00) Zagreb\",\"Europe\\/Athens\":\"(UTC+02:00) Athens\",\"Europe\\/Bucharest\":\"(UTC+02:00) Bucharest\",\"Africa\\/Cairo\":\"(UTC+02:00) Cairo\",\"Africa\\/Harare\":\"(UTC+02:00) Harare\",\"Europe\\/Helsinki\":\"(UTC+02:00) Helsinki\",\"Europe\\/Istanbul\":\"(UTC+02:00) Istanbul\",\"Asia\\/Jerusalem\":\"(UTC+02:00) Jerusalem\",\"Europe\\/Kyiv\":\"(UTC+02:00) Kyiv\",\"Africa\\/Johannesburg\":\"(UTC+02:00) Pretoria\",\"Europe\\/Riga\":\"(UTC+02:00) Riga\",\"Europe\\/Sofia\":\"(UTC+02:00) Sofia\",\"Europe\\/Tallinn\":\"(UTC+02:00) Tallinn\",\"Europe\\/Vilnius\":\"(UTC+02:00) Vilnius\",\"Asia\\/Baghdad\":\"(UTC+03:00) Baghdad\",\"Asia\\/Kuwait\":\"(UTC+03:00) Kuwait\",\"Europe\\/Minsk\":\"(UTC+03:00) Minsk\",\"Africa\\/Nairobi\":\"(UTC+03:00) Nairobi\",\"Asia\\/Riyadh\":\"(UTC+03:00) Riyadh\",\"Europe\\/Volgograd\":\"(UTC+03:00) Volgograd\",\"Asia\\/Tehran\":\"(UTC+03:30) Tehran\",\"Asia\\/Abu_Dhabi\":\"(UTC+04:00) Abu Dhabi\",\"Asia\\/Baku\":\"(UTC+04:00) Baku\",\"Europe\\/Moscow\":\"(UTC+04:00) Moscow\",\"Asia\\/Muscat\":\"(UTC+04:00) Muscat\",\"Europe\\/St_Petersburg\":\"(UTC+04:00) St. Petersburg\",\"Asia\\/Tbilisi\":\"(UTC+04:00) Tbilisi\",\"Asia\\/Yerevan\":\"(UTC+04:00) Yerevan\",\"Asia\\/Kabul\":\"(UTC+04:30) Kabul\",\"Asia\\/Islamabad\":\"(UTC+05:00) Islamabad\",\"Asia\\/Karachi\":\"(UTC+05:00) Karachi\",\"Asia\\/Tashkent\":\"(UTC+05:00) Tashkent\",\"Asia\\/Calcutta\":\"(UTC+05:30) Chennai\",\"Asia\\/Kolkata\":\"(UTC+05:30) Kolkata\",\"Asia\\/Mumbai\":\"(UTC+05:30) Mumbai\",\"Asia\\/New_Delhi\":\"(UTC+05:30) New Delhi\",\"Asia\\/Sri_Jayawardenepura\":\"(UTC+05:30) Sri Jayawardenepura\",\"Asia\\/Katmandu\":\"(UTC+05:45) Kathmandu\",\"Asia\\/Almaty\":\"(UTC+06:00) Almaty\",\"Asia\\/Astana\":\"(UTC+06:00) Astana\",\"Asia\\/Dhaka\":\"(UTC+06:00) Dhaka\",\"Asia\\/Yekaterinburg\":\"(UTC+06:00) Ekaterinburg\",\"Asia\\/Rangoon\":\"(UTC+06:30) Rangoon\",\"Asia\\/Bangkok\":\"(UTC+07:00) Bangkok\",\"Asia\\/Hanoi\":\"(UTC+07:00) Hanoi\",\"Asia\\/Jakarta\":\"(UTC+07:00) Jakarta\",\"Asia\\/Novosibirsk\":\"(UTC+07:00) Novosibirsk\",\"Asia\\/Beijing\":\"(UTC+08:00) Beijing\",\"Asia\\/Chongqing\":\"(UTC+08:00) Chongqing\",\"Asia\\/Hong_Kong\":\"(UTC+08:00) Hong Kong\",\"Asia\\/Krasnoyarsk\":\"(UTC+08:00) Krasnoyarsk\",\"Asia\\/Kuala_Lumpur\":\"(UTC+08:00) Kuala Lumpur\",\"Australia\\/Perth\":\"(UTC+08:00) Perth\",\"Asia\\/Singapore\":\"(UTC+08:00) Singapore\",\"Asia\\/Taipei\":\"(UTC+08:00) Taipei\",\"Asia\\/Ulan_Bator\":\"(UTC+08:00) Ulaan Bataar\",\"Asia\\/Urumqi\":\"(UTC+08:00) Urumqi\",\"Asia\\/Irkutsk\":\"(UTC+09:00) Irkutsk\",\"Asia\\/Osaka\":\"(UTC+09:00) Osaka\",\"Asia\\/Sapporo\":\"(UTC+09:00) Sapporo\",\"Asia\\/Seoul\":\"(UTC+09:00) Seoul\",\"Asia\\/Tokyo\":\"(UTC+09:00) Tokyo\",\"Australia\\/Adelaide\":\"(UTC+09:30) Adelaide\",\"Australia\\/Darwin\":\"(UTC+09:30) Darwin\",\"Australia\\/Brisbane\":\"(UTC+10:00) Brisbane\",\"Australia\\/Canberra\":\"(UTC+10:00) Canberra\",\"Pacific\\/Guam\":\"(UTC+10:00) Guam\",\"Australia\\/Hobart\":\"(UTC+10:00) Hobart\",\"Australia\\/Melbourne\":\"(UTC+10:00) Melbourne\",\"Pacific\\/Port_Moresby\":\"(UTC+10:00) Port Moresby\",\"Australia\\/Sydney\":\"(UTC+10:00) Sydney\",\"Asia\\/Yakutsk\":\"(UTC+10:00) Yakutsk\",\"Asia\\/Vladivostok\":\"(UTC+11:00) Vladivostok\",\"Pacific\\/Auckland\":\"(UTC+12:00) Auckland\",\"Pacific\\/Fiji\":\"(UTC+12:00) Fiji\",\"Pacific\\/Kwajalein\":\"(UTC+12:00) International Date Line West\",\"Asia\\/Kamchatka\":\"(UTC+12:00) Kamchatka\",\"Asia\\/Magadan\":\"(UTC+12:00) Magadan\",\"Pacific\\/Marshall_Is\":\"(UTC+12:00) Marshall Is.\",\"Asia\\/New_Caledonia\":\"(UTC+12:00) New Caledonia\",\"Asia\\/Solomon_Is\":\"(UTC+12:00) Solomon Is.\",\"Pacific\\/Wellington\":\"(UTC+12:00) Wellington\",\"Pacific\\/Tongatapu\":\"(UTC+13:00) Nuku\'alofa\"},\"placeholder\":\"Choose a timezone...\"}', '1', NULL, '1', '0', '0', '0', '11', 'half', NULL, NULL, NULL), +('143', 'directus_users', 'locale', 'string', 'language', '{\"limit\":true}', '1', NULL, '0', '0', '0', '0', '12', 'half', NULL, NULL, NULL), +('144', 'directus_users', 'avatar', 'file', 'file', NULL, '1', NULL, '0', '0', '0', '0', '13', 'full', NULL, NULL, NULL), +('145', 'directus_users', 'theme', 'string', 'radio-buttons', '{\"format\":true,\"choices\":{\"auto\":\"Auto\",\"light\":\"Light\",\"dark\":\"Dark\"}}', '1', NULL, '0', '0', '0', '0', '14', 'full', NULL, NULL, NULL), +('146', 'directus_users', '2fa_secret', 'string', '2fa-secret', NULL, '1', NULL, '0', '1', '0', '0', '15', 'full', NULL, NULL, NULL), +('147', 'directus_users', 'locale_options', 'json', 'json', NULL, '1', NULL, '0', '0', '1', '1', '16', 'full', NULL, NULL, NULL), +('148', 'directus_users', 'token', 'string', 'text-input', NULL, '1', NULL, '0', '0', '1', '1', '17', 'full', NULL, NULL, NULL), +('149', 'directus_users', 'last_access_on', 'datetime', 'datetime', NULL, '1', NULL, '0', '1', '1', '0', '18', 'full', NULL, NULL, NULL), +('150', 'directus_users', 'last_page', 'string', 'text-input', NULL, '1', NULL, '0', '1', '1', '1', '19', 'full', NULL, NULL, NULL), +('151', 'directus_users', 'external_id', 'string', 'text-input', NULL, '1', NULL, '0', '1', '20', '0', NULL, 'full', NULL, NULL, NULL), +('152', 'directus_user_sessions', 'id', 'integer', 'primary-key', NULL, '1', NULL, '1', '0', '1', '0', NULL, 'full', NULL, NULL, NULL), +('153', 'directus_user_sessions', 'user', 'user', 'user', NULL, '0', NULL, '1', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('154', 'directus_user_sessions', 'token_type', 'string', 'text-input', NULL, '0', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('155', 'directus_user_sessions', 'token', 'string', 'text-input', NULL, '0', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('156', 'directus_user_sessions', 'ip_address', 'string', 'text-input', NULL, '0', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('157', 'directus_user_sessions', 'user_agent', 'string', 'text-input', NULL, '0', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('158', 'directus_user_sessions', 'created_on', 'datetime', 'datetime', NULL, '0', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('159', 'directus_user_sessions', 'token_expired_at', 'datetime', 'datetime', NULL, '0', NULL, '0', '0', '0', '0', NULL, 'full', NULL, NULL, NULL), +('160', 'directus_webhooks', 'id', 'integer', 'primary-key', NULL, '1', NULL, '1', '0', '1', '0', NULL, 'full', NULL, NULL, NULL), +('161', 'directus_webhooks', 'status', 'status', 'status', '{\"status_mapping\":{\"active\":{\"name\":\"Active\",\"value\":\"active\",\"text_color\":\"white\",\"background_color\":\"green\",\"browse_subdued\":false,\"browse_badge\":true,\"soft_delete\":false,\"published\":true},\"inactive\":{\"name\":\"Inactive\",\"value\":\"inactive\",\"text_color\":\"white\",\"background_color\":\"blue-grey\",\"browse_subdued\":true,\"browse_badge\":true,\"soft_delete\":false,\"published\":false}}}', '1', NULL, '0', '0', '0', '0', '1', 'full', NULL, NULL, NULL), +('162', 'directus_webhooks', 'http_action', 'string', 'dropdown', '{\"choices\":{\"get\":\"GET\",\"post\":\"POST\"}}', '1', NULL, '1', '0', '0', '0', '2', 'half-space', NULL, NULL, NULL), +('163', 'directus_webhooks', 'url', 'string', 'text-input', '{\"placeholder\":\"https:\\/\\/example.com\",\"iconRight\":\"link\"}', '1', NULL, '1', '0', '0', '0', '3', 'full', NULL, '', NULL), +('164', 'directus_webhooks', 'collection', 'string', 'collections', NULL, '1', NULL, '1', '0', '0', '0', '4', 'half', NULL, '', NULL), +('165', 'directus_webhooks', 'directus_action', 'string', 'dropdown', '{\"choices\":{\"item.create:after\":\"Create\",\"item.update:after\":\"Update\",\"item.delete:after\":\"Delete\"}}', '1', NULL, '1', '0', '0', '0', '5', 'half', NULL, '', NULL), +('166', 'directus_webhooks', 'info', 'alias', 'divider', '{\"style\":\"medium\",\"title\":\"How Webhooks Work\",\"hr\":true,\"margin\":false,\"description\":\"When the selected action occurs for the selected collection, Directus will send an HTTP request to the above URL.\"}', '1', NULL, '0', '0', '0', '1', '6', 'full', NULL, NULL, NULL); + +INSERT INTO `directus_migrations` (`version`, `migration_name`, `start_time`, `end_time`, `breakpoint`) VALUES ('20180220023123', 'CreateFieldsTable', '2019-12-05 09:36:20', '2019-12-05 09:36:20', '0'), +('20180220023138', 'CreateActivityTable', '2019-12-05 09:36:20', '2019-12-05 09:36:20', '0'), +('20180220023152', 'CreateCollectionsPresetsTable', '2019-12-05 09:36:20', '2019-12-05 09:36:20', '0'), +('20180220023157', 'CreateCollectionsTable', '2019-12-05 09:36:20', '2019-12-05 09:36:20', '0'), +('20180220023208', 'CreateFilesTable', '2019-12-05 09:36:20', '2019-12-05 09:36:20', '0'), +('20180220023213', 'CreateFoldersTable', '2019-12-05 09:36:20', '2019-12-05 09:36:20', '0'), +('20180220023217', 'CreateRolesTable', '2019-12-05 09:36:20', '2019-12-05 09:36:20', '0'), +('20180220023226', 'CreatePermissionsTable', '2019-12-05 09:36:20', '2019-12-05 09:36:20', '0'), +('20180220023232', 'CreateRelationsTable', '2019-12-05 09:36:20', '2019-12-05 09:36:20', '0'), +('20180220023238', 'CreateRevisionsTable', '2019-12-05 09:36:20', '2019-12-05 09:36:20', '0'), +('20180220023243', 'CreateSettingsTable', '2019-12-05 09:36:20', '2019-12-05 09:36:20', '0'), +('20180220023248', 'CreateUsersTable', '2019-12-05 09:36:20', '2019-12-05 09:36:20', '0'), +('20181022175715', 'Upgrade070003', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20181102153600', 'TimezoneChoices', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20181105165224', 'Upgrade070006', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20181122195602', 'LocaleInterface', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20181123171520', 'RemoveScope', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20181210204720', 'AddTrustedProxiesSettingField', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20181222023800', 'AddProjectUrlSettingField', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20181227042755', 'IncreaseUsersLastPageLength', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190104155309', 'AddUsersEmailValidation', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190111193724', 'AddAppUrlSettingField', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190111212736', 'AddMissingSettingsField', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190118181424', 'AddRolesUsersField', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190130215921', 'AddFilesChecksumField', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190318173400', 'AddNavOverride', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190412122400', 'SetPasswordTypeToHash', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190412123000', 'UseFileInterface', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190412145800', 'SetO2mOptionsRoles', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190415125300', 'SetWidth', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190419154400', 'SettingsFields', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190419161200', 'CollectionNotes', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190419173000', 'MiscRequiredFields', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190422131600', 'UseJson', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190426156200', 'SetNullableValueFieldSettingsTable', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190520094300', 'UseTimeline', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190614103321', 'AddUsers2faSecretField', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190618190024', 'AddEnforce2faRoleField', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190626114228', 'AddFileNamingInSetting', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190702092323', 'AddLoginAttemptsAllowedSetting', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190704063752', 'UpdateIstanbulTimezone', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190708095522', 'AddFileExtensionSetting', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190709053719', 'AddFileMaxSizeSetting', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190722110232', 'PasswordValidationSettingField', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190726064001', 'UpdateNoteForDefaultLimit', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190819070856', 'UpdateDirectusFieldsField', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20190912072543', 'CreateUserSessions', '2019-12-05 09:36:20', '2019-12-05 09:36:20', '0'), +('20190917090849', 'CreateWebHooks', '2019-12-05 09:36:20', '2019-12-05 09:36:20', '0'), +('20191123053252', 'UpdateDirectusFilesField', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20191129123300', 'UseNewWysiwyg', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20191202164200', 'AddUserSessions', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20191202164201', 'AddWebhooks', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20191202164202', 'RemoveActivitySeen', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20191202164203', 'ConvertUserRoles', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20191202164204', 'UpdateDirectusUsers', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20191202164205', 'UpdateDirectusSettings', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20191202164206', 'UpdateDirectusFiles', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20191202164207', 'UpdateDirectusRoles', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20191202164208', 'ResetDirectusRelations', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20191202164209', 'ResetDirectusFields', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20191203105400', 'AddHashFiledownloadIfEmpty', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'), +('20191204151300', 'UseCorrectWysiwyg', '2019-12-05 14:36:20', '2019-12-05 14:36:20', '0'); + +INSERT INTO `directus_relations` (`id`, `collection_many`, `field_many`, `collection_one`, `field_one`, `junction_field`) VALUES ('1', 'directus_activity', 'action_by', 'directus_users', NULL, NULL), +('2', 'directus_collections_presets', 'user', 'directus_users', NULL, NULL), +('3', 'directus_collections_presets', 'group', 'directus_groups', NULL, NULL), +('4', 'directus_fields', 'collection', 'directus_collections', 'fields', NULL), +('5', 'directus_files', 'uploaded_by', 'directus_users', NULL, NULL), +('6', 'directus_files', 'folder', 'directus_folders', NULL, NULL), +('7', 'directus_folders', 'parent_folder', 'directus_folders', NULL, NULL), +('8', 'directus_permissions', 'group', 'directus_groups', NULL, NULL), +('9', 'directus_revisions', 'activity', 'directus_activity', NULL, NULL), +('10', 'directus_users', 'role', 'directus_roles', 'users', NULL), +('11', 'directus_users', 'avatar', 'directus_files', NULL, NULL); + +INSERT INTO `directus_roles` (`id`, `name`, `description`, `ip_whitelist`, `external_id`, `module_listing`, `collection_listing`, `enforce_2fa`) VALUES ('1', 'Administrator', 'Admins have access to all managed data within the system by default', NULL, NULL, NULL, NULL, '0'), +('2', 'Public', 'Controls what API data is publicly available without authenticating', NULL, NULL, NULL, NULL, '0'); + +INSERT INTO `directus_settings` (`id`, `key`, `value`) VALUES ('1', 'project_url', ''), +('2', 'project_logo', ''), +('3', 'project_color', '#13181a'), +('4', 'project_foreground', ''), +('5', 'project_background', ''), +('6', 'default_locale', 'en-US'), +('7', 'telemetry', '1'), +('8', 'default_limit', '200'), +('9', 'sort_null_last', '1'), +('10', 'password_policy', ''), +('11', 'auto_sign_out', '10080'), +('12', 'login_attempts_allowed', '10'), +('13', 'trusted_proxies', ''), +('14', 'file_max_size', '100MB'), +('15', 'file_mimetype_whitelist', ''), +('16', 'file_naming', 'uuid'), +('17', 'youtube_api_key', ''), +('18', 'asset_whitelist', '[{\"key\":\"thumbnail\",\"width\":200,\"height\":200,\"fit\":\"contain\",\"quality\":80}]'), +('19', 'asset_whitelist_system', '[{\"key\":\"card\",\"width\":200,\"height\":200,\"fit\":\"crop\",\"quality\":80},{\"key\":\"avatar\",\"width\":100,\"height\":100,\"fit\":\"crop\",\"quality\":80}]'); + +INSERT INTO `directus_users` (`id`, `status`, `role`, `first_name`, `last_name`, `email`, `password`, `token`, `timezone`, `locale`, `locale_options`, `avatar`, `company`, `title`, `email_notifications`, `last_access_on`, `last_page`, `external_id`, `theme`, `2fa_secret`) VALUES ('1', 'active', '1', 'Admin', 'User', 'admin@example.com', '$2y$10$CifjZIWHTjZeQktU53JK6Of1LmulMj9D02XrC3kca/qXyWbmZTxvO', 'admin', 'America/New_York', 'en-US', NULL, NULL, NULL, NULL, '1', '2019-12-05 09:39:19', NULL, NULL, 'auto', NULL); + + + + +/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */; /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; /*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */; -/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; +/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; +/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; +/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; +/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; \ No newline at end of file From dfdfe20706db6f0b98bb5d1576502871ddaad535 Mon Sep 17 00:00:00 2001 From: Rijk van Zanten Date: Thu, 5 Dec 2019 10:26:38 -0500 Subject: [PATCH 03/11] v8.0.2 (#1529) * Fix reference to get_random_string in migrations * Bump version --- migrations/upgrades/20191202164206_update_directus_files.php | 1 + .../upgrades/20191203105400_add_hash_filedownload_if_empty.php | 1 + src/core/Directus/Application/Application.php | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/migrations/upgrades/20191202164206_update_directus_files.php b/migrations/upgrades/20191202164206_update_directus_files.php index 76af64b088..e1893fbfce 100644 --- a/migrations/upgrades/20191202164206_update_directus_files.php +++ b/migrations/upgrades/20191202164206_update_directus_files.php @@ -1,6 +1,7 @@ Date: Thu, 5 Dec 2019 20:10:40 -0500 Subject: [PATCH 04/11] v8.1.0 (#1532) * Add migration for new system thumbnail sizes * Check if array keys exist before use and pass filename_disk where needed (#1530) * Repair / implement folders endpoint (#1531) * Bump version --- ...150000_update_directus_thumbnail_sizes.php | 61 ++++++++++ src/core/Directus/Application/Application.php | 2 +- src/core/Directus/Services/FilesServices.php | 93 +++----------- src/core/Directus/Services/FoldersService.php | 89 ++++++++++++++ src/endpoints/Files.php | 97 --------------- src/endpoints/Folders.php | 114 ++++++++++++++++++ src/helpers/file.php | 1 + src/web.php | 6 +- 8 files changed, 290 insertions(+), 173 deletions(-) create mode 100644 migrations/upgrades/20191205150000_update_directus_thumbnail_sizes.php create mode 100644 src/core/Directus/Services/FoldersService.php create mode 100644 src/endpoints/Folders.php diff --git a/migrations/upgrades/20191205150000_update_directus_thumbnail_sizes.php b/migrations/upgrades/20191205150000_update_directus_thumbnail_sizes.php new file mode 100644 index 0000000000..b1e2891c4d --- /dev/null +++ b/migrations/upgrades/20191205150000_update_directus_thumbnail_sizes.php @@ -0,0 +1,61 @@ +execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_settings', + ['value' => json_encode([ + [ + 'key' => 'directus-small-crop', + 'width' => 64, + 'height' => 64, + 'fit' => 'crop', + 'quality' => 80 + ], + [ + 'key' => 'directus-small-contain', + 'width' => 64, + 'height' => 64, + 'fit' => 'contain', + 'quality' => 80 + ], + [ + 'key' => 'directus-medium-crop', + 'width' => 300, + 'height' => 300, + 'fit' => 'crop', + 'quality' => 80 + ], + [ + 'key' => 'directus-medium-contain', + 'width' => 300, + 'height' => 300, + 'fit' => 'contain', + 'quality' => 80 + ], + [ + 'key' => 'directus-large-crop', + 'width' => 800, + 'height' => 600, + 'fit' => 'crop', + 'quality' => 80 + ], + [ + 'key' => 'directus-large-contain', + 'width' => 800, + 'height' => 600, + 'fit' => 'contain', + 'quality' => 80 + ] + ])], + ['key' => 'asset_whitelist_system'] + )); + } +} diff --git a/src/core/Directus/Application/Application.php b/src/core/Directus/Application/Application.php index 76cdd0b635..51c98b0463 100644 --- a/src/core/Directus/Application/Application.php +++ b/src/core/Directus/Application/Application.php @@ -13,7 +13,7 @@ class Application extends App * * @var string */ - const DIRECTUS_VERSION = '8.0.2'; + const DIRECTUS_VERSION = '8.1.0'; /** * NOT USED diff --git a/src/core/Directus/Services/FilesServices.php b/src/core/Directus/Services/FilesServices.php index 2f17049484..2921d299fc 100644 --- a/src/core/Directus/Services/FilesServices.php +++ b/src/core/Directus/Services/FilesServices.php @@ -70,21 +70,24 @@ public function create(array $data, array $params = []) public function getSaveData($data, $isUpdate){ $dataInfo = []; $files = $this->container->get('files'); - if (is_a_url($data['data'])) { + + if (array_key_exists('data', $data) && is_a_url($data['data'])) { $dataInfo = $files->getLink($data['data']); // Set the URL payload data $data['data'] = ArrayUtils::get($dataInfo, 'data'); $data['filename_disk'] = ArrayUtils::get($dataInfo, 'filename_disk'); - } else if (!is_object($data['data'])) { + } else if (array_key_exists('data', $data) && !is_object($data['data'])) { $dataInfo = $files->getDataInfo($data['data']); } + $type = ArrayUtils::get($dataInfo, 'type', ArrayUtils::get($data, 'type')); if (strpos($type, 'embed/') === 0) { $recordData = $files->saveEmbedData(array_merge($dataInfo, ArrayUtils::pick($data, ['filename_disk']))); } else { - $recordData = $files->saveData($data['data'], $data['filename_disk'],$isUpdate); + $newFileContents = array_key_exists('data', $data) ? $data['data'] : null; + $recordData = $files->saveData($newFileContents, $data['filename_disk'], $isUpdate); } // NOTE: Use the user input title, tags, description and location when exists. @@ -96,7 +99,7 @@ public function getSaveData($data, $isUpdate){ ])); if(!$isUpdate){ - $recordData['private_hash'] = get_random_string(); + $recordData['private_hash'] = get_random_string(); } return ArrayUtils::omit(array_merge($data,$recordData),['data','html']); @@ -151,7 +154,7 @@ public function update($id, array $data, array $params = []) $currentItem = $tableGateway->getOneData($id); $currentFileName = ArrayUtils::get($currentItem, 'filename_disk'); - if ($data['filename_disk'] && $data['filename_disk'] !== $currentFileName) { + if (array_key_exists('filename_disk', $data) && $data['filename_disk'] !== $currentFileName) { $oldFilePath = $currentFileName; $newFilePath = $data['filename_disk']; @@ -162,6 +165,17 @@ public function update($id, array $data, array $params = []) } } + // getSaveData requires filename_disk to be set, in order for Filesystem/Files to read the file info + $fileName = $currentFileName; + + // If the user provided their own filename, the file has been renamed above. In that case, pass on + // the new filename + if (array_key_exists('filename_disk', $data)) { + $fileName = $data['filename_disk']; + } + + $data['filename_disk'] = $fileName; + $recordData = $this->getSaveData($data, true); $newFile = $tableGateway->updateRecord($id, $recordData, $this->getCRUDParams($params)); @@ -197,75 +211,6 @@ public function findAll(array $params = []) return $this->getItemsAndSetResponseCacheTags($tableGateway, $params); } - public function createFolder(array $data, array $params = []) - { - $collection = 'directus_folders'; - $this->enforceCreatePermissions($collection, $data, $params); - $this->validatePayload($collection, null, $data, $params); - - $foldersTableGateway = $this->createTableGateway($collection); - - $newFolder = $foldersTableGateway->createRecord($data, $this->getCRUDParams($params)); - - return $foldersTableGateway->wrapData( - $newFolder->toArray(), - true, - ArrayUtils::get($params, 'meta') - ); - } - - public function findFolder($id, array $params = []) - { - $foldersTableGateway = $this->createTableGateway('directus_folders'); - $params['id'] = $id; - - return $this->getItemsAndSetResponseCacheTags($foldersTableGateway, $params); - } - - public function findFolderByIds($id, array $params = []) - { - $foldersTableGateway = $this->createTableGateway('directus_folders'); - - return $this->getItemsByIdsAndSetResponseCacheTags($foldersTableGateway, $id, $params); - } - - public function updateFolder($id, array $data, array $params = []) - { - $collectionName = 'directus_folders'; - $this->enforceUpdatePermissions($collectionName, $data, $params); - $this->checkItemExists($collectionName, $id); - - $foldersTableGateway = $this->createTableGateway('directus_folders'); - $group = $foldersTableGateway->updateRecord($id, $data, $this->getCRUDParams($params)); - - return $foldersTableGateway->wrapData( - $group->toArray(), - true, - ArrayUtils::get($params, 'meta') - ); - } - - public function findAllFolders(array $params = []) - { - $foldersTableGateway = $this->createTableGateway('directus_folders'); - - return $this->getItemsAndSetResponseCacheTags($foldersTableGateway, $params); - } - - public function deleteFolder($id, array $params = []) - { - $this->enforcePermissions('directus_folders', [], $params); - - $foldersTableGateway = $this->createTableGateway('directus_folders'); - // NOTE: check if item exists - // TODO: As noted in other places make a light function to check for it - $this->getItemsAndSetResponseCacheTags($foldersTableGateway, [ - 'id' => $id - ]); - - return $foldersTableGateway->deleteRecord($id, $this->getCRUDParams($params)); - } - /** * @param array $items * @param array $params diff --git a/src/core/Directus/Services/FoldersService.php b/src/core/Directus/Services/FoldersService.php new file mode 100644 index 0000000000..1dafe6b009 --- /dev/null +++ b/src/core/Directus/Services/FoldersService.php @@ -0,0 +1,89 @@ +collection = SchemaManager::COLLECTION_FOLDERS; + } + + public function createFolder(array $data, array $params = []) + { + $this->enforceCreatePermissions($this->$collection, $data, $params); + $this->validatePayload($this->$collection, null, $data, $params); + + $foldersTableGateway = $this->createTableGateway($this->$collection); + + $newFolder = $foldersTableGateway->createRecord($data, $this->getCRUDParams($params)); + + return $foldersTableGateway->wrapData( + $newFolder->toArray(), + true, + ArrayUtils::get($params, 'meta') + ); + } + + public function findFolder($id, array $params = []) + { + $foldersTableGateway = $this->createTableGateway('directus_folders'); + $params['id'] = $id; + + return $this->getItemsAndSetResponseCacheTags($foldersTableGateway, $params); + } + + public function findFolderByIds($id, array $params = []) + { + $foldersTableGateway = $this->createTableGateway('directus_folders'); + + return $this->getItemsByIdsAndSetResponseCacheTags($foldersTableGateway, $id, $params); + } + + public function updateFolder($id, array $data, array $params = []) + { + $this->enforceUpdatePermissions($this->collection, $data, $params); + $this->checkItemExists($this->collection, $id); + + $foldersTableGateway = $this->createTableGateway('directus_folders'); + $group = $foldersTableGateway->updateRecord($id, $data, $this->getCRUDParams($params)); + + return $foldersTableGateway->wrapData( + $group->toArray(), + true, + ArrayUtils::get($params, 'meta') + ); + } + + public function findAllFolders(array $params = []) + { + $foldersTableGateway = $this->createTableGateway('directus_folders'); + + return $this->getItemsAndSetResponseCacheTags($foldersTableGateway, $params); + } + + public function deleteFolder($id, array $params = []) + { + $this->enforcePermissions($this->collection, [], $params); + + $foldersTableGateway = $this->createTableGateway('directus_folders'); + // NOTE: check if item exists + // TODO: As noted in other places make a light function to check for it + $this->getItemsAndSetResponseCacheTags($foldersTableGateway, [ + 'id' => $id + ]); + + return $foldersTableGateway->deleteRecord($id, $this->getCRUDParams($params)); + } +} diff --git a/src/endpoints/Files.php b/src/endpoints/Files.php index c3b69fb762..69f595351e 100644 --- a/src/endpoints/Files.php +++ b/src/endpoints/Files.php @@ -31,16 +31,6 @@ public function __invoke(Application $app) $app->delete('/{id}', [$this, 'delete']); $app->get('', [$this, 'all']); - // Folders - $controller = $this; - $app->group('/folders', function () use ($controller) { - $this->post('', [$controller, 'createFolder']); - $this->get('/{id:[0-9]+}', [$controller, 'readFolder']); - $this->patch('/{id:[0-9]+}', [$controller, 'updateFolder']); - $this->delete('/{id:[0-9]+}', [$controller, 'deleteFolder']); - $this->get('', [$controller, 'allFolder']); - }); - // Revisions $app->get('/{id}/revisions', [$this, 'fileRevisions']); $app->get('/{id}/revisions/{offset}', [$this, 'oneFileRevision']); @@ -164,93 +154,6 @@ public function all(Request $request, Response $response) return $this->responseWithData($request, $response, $responseData); } - /** - * @param Request $request - * @param Response $response - * - * @return Response - */ - public function createFolder(Request $request, Response $response) - { - $this->validateRequestPayload($request); - $service = new FilesServices($this->container); - $responseData = $service->createFolder( - $request->getParsedBody(), - $request->getQueryParams() - ); - - return $this->responseWithData($request, $response, $responseData); - } - - /** - * @param Request $request - * @param Response $response - * - * @return Response - */ - public function readFolder(Request $request, Response $response) - { - $service = new FilesServices($this->container); - $responseData = $service->findFolderByIds( - $request->getAttribute('id'), - ArrayUtils::pick($request->getQueryParams(), ['fields', 'meta']) - ); - - return $this->responseWithData($request, $response, $responseData); - } - - /** - * @param Request $request - * @param Response $response - * - * @return Response - */ - public function updateFolder(Request $request, Response $response) - { - $this->validateRequestPayload($request); - $service = new FilesServices($this->container); - $responseData = $service->updateFolder( - $request->getAttribute('id'), - $request->getParsedBody(), - $request->getQueryParams() - ); - - return $this->responseWithData($request, $response, $responseData); - } - - /** - * @param Request $request - * @param Response $response - * - * @return Response - */ - public function allFolder(Request $request, Response $response) - { - $service = new FilesServices($this->container); - $responseData = $service->findAllFolders( - $request->getQueryParams() - ); - - return $this->responseWithData($request, $response, $responseData); - } - - /** - * @param Request $request - * @param Response $response - * - * @return Response - */ - public function deleteFolder(Request $request, Response $response) - { - $service = new FilesServices($this->container); - $service->deleteFolder( - $request->getAttribute('id'), - $request->getQueryParams() - ); - - return $this->responseWithData($request, $response, []); - } - /** * @param Request $request * @param Response $response diff --git a/src/endpoints/Folders.php b/src/endpoints/Folders.php new file mode 100644 index 0000000000..545894f6c2 --- /dev/null +++ b/src/endpoints/Folders.php @@ -0,0 +1,114 @@ +get('', [$this, 'allFolders']); + $app->post('', [$this, 'createFolder']); + $app->get('/{id:[0-9]+}', [$this, 'readFolder']); + $app->patch('/{id:[0-9]+}', [$this, 'updateFolder']); + $app->delete('/{id:[0-9]+}', [$this, 'deleteFolder']); + } + + /** + * @param Request $request + * @param Response $response + * + * @return Response + */ + public function allFolders(Request $request, Response $response) + { + $service = new FoldersService($this->container); + $responseData = $service->findAllFolders( + $request->getQueryParams() + ); + + return $this->responseWithData($request, $response, $responseData); + } + + /** + * @param Request $request + * @param Response $response + * + * @return Response + */ + public function createFolder(Request $request, Response $response) + { + $this->validateRequestPayload($request); + $service = new FoldersService($this->container); + $responseData = $service->createFolder( + $request->getParsedBody(), + $request->getQueryParams() + ); + + return $this->responseWithData($request, $response, $responseData); + } + + /** + * @param Request $request + * @param Response $response + * + * @return Response + */ + public function readFolder(Request $request, Response $response) + { + $service = new FoldersService($this->container); + $responseData = $service->findFolderByIds( + $request->getAttribute('id'), + ArrayUtils::pick($request->getQueryParams(), ['fields', 'meta']) + ); + + return $this->responseWithData($request, $response, $responseData); + } + + /** + * @param Request $request + * @param Response $response + * + * @return Response + */ + public function updateFolder(Request $request, Response $response) + { + $this->validateRequestPayload($request); + $service = new FoldersService($this->container); + $responseData = $service->updateFolder( + $request->getAttribute('id'), + $request->getParsedBody(), + $request->getQueryParams() + ); + + return $this->responseWithData($request, $response, $responseData); + } + + + /** + * @param Request $request + * @param Response $response + * + * @return Response + */ + public function deleteFolder(Request $request, Response $response) + { + $service = new FoldersService($this->container); + $service->deleteFolder( + $request->getAttribute('id'), + $request->getQueryParams() + ); + + return $this->responseWithData($request, $response, []); + } +} diff --git a/src/helpers/file.php b/src/helpers/file.php index 83bea29337..9642683474 100644 --- a/src/helpers/file.php +++ b/src/helpers/file.php @@ -148,6 +148,7 @@ function append_storage_information(array $rows) // Add thumbnails if the asset is an image $search = 'image'; if ( + array_key_exists('type', $row) && substr($row['type'], 0, strlen($search)) === $search && $row['type'] !== 'image/svg+xml' // SVGs aren't manipulatable bitmaps ) { diff --git a/src/web.php b/src/web.php index 91f34c8853..20895ac0d9 100644 --- a/src/web.php +++ b/src/web.php @@ -138,7 +138,7 @@ $app->get('/{project}/assets/{id}', \Directus\Api\Routes\Assets::class); $app->group('/{project}', function () use ($middleware) { - + $this->get('/', \Directus\Api\Routes\ProjectHome::class) ->add($middleware['auth_user']) ->add($middleware['rate_limit_user']) @@ -164,6 +164,10 @@ ->add($middleware['rate_limit_user']) ->add($middleware['auth']) ->add($middleware['table_gateway']); + $this->group('/folders', \Directus\Api\Routes\Folders::class) + ->add($middleware['rate_limit_user']) + ->add($middleware['auth']) + ->add($middleware['table_gateway']); $this->group('/items', \Directus\Api\Routes\Items::class) ->add($middleware['rate_limit_user']) ->add($middleware['auth']) From 667f1ffc2e5f4be31f30c2e386f7cc77d7322ca2 Mon Sep 17 00:00:00 2001 From: Rijk van Zanten Date: Mon, 9 Dec 2019 15:13:59 -0500 Subject: [PATCH 05/11] v8.2.0 (#1540) * Use correct system keys on new installations * Don't use tablegatewaymiddleware for project deletion (#1535) * Use correct settings for collection / module listing (#1537) * Add project public note field to settings (#1538) * Add project public note to settings * Return public note in /:project endpoint * Return the relative url of thumbnails including root folder (#1539) * Bump version --- .../20180220023217_create_roles_table.php | 55 +------------ .../20180220023243_create_settings_table.php | 74 +++++++++++++---- ...20191209130300_add_project_public_note.php | 82 +++++++++++++++++++ ...9141700_set_options_collection_listing.php | 29 +++++++ src/core/Directus/Application/Application.php | 2 +- src/endpoints/Server.php | 4 +- src/helpers/all.php | 15 ++++ src/helpers/file.php | 15 +--- src/helpers/settings.php | 47 +++++++++-- 9 files changed, 232 insertions(+), 91 deletions(-) create mode 100644 migrations/upgrades/20191209130300_add_project_public_note.php create mode 100644 migrations/upgrades/20191209141700_set_options_collection_listing.php diff --git a/migrations/install/20180220023217_create_roles_table.php b/migrations/install/20180220023217_create_roles_table.php index 31da7712bf..bdd6041ab7 100644 --- a/migrations/install/20180220023217_create_roles_table.php +++ b/migrations/install/20180220023217_create_roles_table.php @@ -125,28 +125,7 @@ public function change() 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, 'interface' => 'repeater', 'locked' => 1, - 'options' => '{ - "fields": [ - { - "field": "name", - "interface": "text-input", - "type": "string", - "width": "half" - }, - { - "field": "link", - "interface": "text-input", - "type": "string", - "width": "half" - }, - { - "field": "icon", - "interface": "icon", - "type": "string", - "width": "full" - } - ] - }' + 'options' => '{"template":"{{ name }}","createItemText":"Add Module","fields":[{"field":"name","interface":"text-input","type":"string","width":"half"},{"field":"link","interface":"text-input","type":"string","width":"half"},{"field":"icon","interface":"icon","type":"string","width":"full"}]}' ], [ 'collection' => 'directus_roles', @@ -154,37 +133,7 @@ public function change() 'type' => \Directus\Database\Schema\DataTypes::TYPE_JSON, 'interface' => 'repeater', 'locked' => 1, - 'options' => '{ - "fields": [ - { - "field": "groups", - "width": "full", - "interface": "repeater", - "type": "JSON", - "options": { - "template": "{{ label }}", - "fields": [ - { - "field": "label", - "interface": "text-input", - "type": "string" - }, - { - "field": "value", - "interface": "text-input", - "type": "string" - }, - { - "field": "icon", - "width": "full", - "interface": "icon", - "type": "string" - } - ] - } - } - ] - }' + 'options' => '{"template":"{{ group_name }}","createItemText":"Add Group","fields":[{"field":"group_name","width":"full","interface":"text-input","type":"string"},{"field":"collections","interface":"repeater","type":"JSON","options":{"createItemText":"Add Collection","fields":[{"field":"collection","type":"string","interface":"collections","width":"full"}]}}]}' ], ]; diff --git a/migrations/install/20180220023243_create_settings_table.php b/migrations/install/20180220023243_create_settings_table.php index 7223c02ea6..a880ce96ab 100644 --- a/migrations/install/20180220023243_create_settings_table.php +++ b/migrations/install/20180220023243_create_settings_table.php @@ -94,6 +94,16 @@ public function change() 'note' => 'Full-screen background for the login page', 'sort' => 6 ], + [ + 'collection' => 'directus_settings', + 'field' => 'project_public_note', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'markdown', + 'locked' => 1, + 'width' => 'full', + 'note' => 'This value will be shown on the public pages of the app', + 'sort' => 7 + ], [ 'collection' => 'directus_settings', 'field' => 'default_locale', @@ -102,7 +112,7 @@ public function change() 'locked' => 1, 'width' => 'half', 'note' => 'Default locale for Directus Users', - 'sort' => 7, + 'sort' => 8, 'options' => json_encode([ 'limit' => true ]) @@ -115,7 +125,7 @@ public function change() 'locked' => 1, 'width' => 'half', 'note' => 'Learn More', - 'sort' => 8 + 'sort' => 9 ], [ 'collection' => 'directus_settings', @@ -130,7 +140,7 @@ public function change() 'locked' => 1, 'width' => 'full', 'hidden_browse' => 1, - 'sort' => 10 + 'sort' => 11 ], [ 'collection' => 'directus_settings', @@ -144,7 +154,7 @@ public function change() 'required' => 1, 'width' => 'half', 'note' => 'Default item count in API and App responses', - 'sort' => 11 + 'sort' => 12 ], [ 'collection' => 'directus_settings', @@ -154,7 +164,7 @@ public function change() 'locked' => 1, 'note' => 'NULL values are sorted last', 'width' => 'half', - 'sort' => 12 + 'sort' => 13 ], [ 'collection' => 'directus_settings', @@ -377,7 +387,7 @@ public function change() ], [ 'key' => 'project_color', - 'value' => '#13181a', + 'value' => '#263238', ], [ 'key' => 'project_foreground', @@ -387,6 +397,10 @@ public function change() 'key' => 'project_background', 'value' => '', ], + [ + 'key' => 'project_public_note', + 'value' => '', + ], [ 'key' => 'default_locale', 'value' => 'en-US', @@ -451,18 +465,46 @@ public function change() 'key' => 'asset_whitelist_system', 'value' => json_encode([ [ - "key" => "card", - "width" => 200, - "height" => 200, - "fit" => "crop", - "quality" => 80 + 'key' => 'directus-small-crop', + 'width' => 64, + 'height' => 64, + 'fit' => 'crop', + 'quality' => 80 ], [ - "key" => "avatar", - "width" => 100, - "height" => 100, - "fit" => "crop", - "quality" => 80 + 'key' => 'directus-small-contain', + 'width' => 64, + 'height' => 64, + 'fit' => 'contain', + 'quality' => 80 + ], + [ + 'key' => 'directus-medium-crop', + 'width' => 300, + 'height' => 300, + 'fit' => 'crop', + 'quality' => 80 + ], + [ + 'key' => 'directus-medium-contain', + 'width' => 300, + 'height' => 300, + 'fit' => 'contain', + 'quality' => 80 + ], + [ + 'key' => 'directus-large-crop', + 'width' => 800, + 'height' => 600, + 'fit' => 'crop', + 'quality' => 80 + ], + [ + 'key' => 'directus-large-contain', + 'width' => 800, + 'height' => 600, + 'fit' => 'contain', + 'quality' => 80 ] ]) ] diff --git a/migrations/upgrades/20191209130300_add_project_public_note.php b/migrations/upgrades/20191209130300_add_project_public_note.php new file mode 100644 index 0000000000..86e14a38e0 --- /dev/null +++ b/migrations/upgrades/20191209130300_add_project_public_note.php @@ -0,0 +1,82 @@ +table('directus_fields'); + $settingsTable = $this->table('directus_settings'); + + $exists = $this->fetchRow('SELECT `key` FROM directus_settings WHERE `key` = "project_public_note";'); + + if ($exists !== false) return; + + $settingsTable->insert([ + 'key' => 'project_public_note', + 'value' => '' + ]); + + $fieldsTable->insert([ + 'collection' => 'directus_settings', + 'field' => 'project_public_note', + 'type' => \Directus\Database\Schema\DataTypes::TYPE_STRING, + 'interface' => 'markdown', + 'locked' => 1, + 'width' => 'full', + 'note' => 'This value will be shown on the public pages of the app', + 'sort' => 7 + ]); + + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + [ + 'sort' => 8 + ], + ['collection' => 'directus_settings', 'field' => 'default_locale'] + )); + + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + [ + 'sort' => 9 + ], + ['collection' => 'directus_settings', 'field' => 'telemetry'] + )); + + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + [ + 'sort' => 10 + ], + ['collection' => 'directus_settings', 'field' => 'data_divider'] + )); + + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + [ + 'sort' => 11 + ], + ['collection' => 'directus_settings', 'field' => 'default_limit'] + )); + + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + [ + 'sort' => 12 + ], + ['collection' => 'directus_settings', 'field' => 'sort_null_last'] + )); + + $fieldsTable->save(); + $settingsTable->save(); + } +} diff --git a/migrations/upgrades/20191209141700_set_options_collection_listing.php b/migrations/upgrades/20191209141700_set_options_collection_listing.php new file mode 100644 index 0000000000..ce9c3a8ab3 --- /dev/null +++ b/migrations/upgrades/20191209141700_set_options_collection_listing.php @@ -0,0 +1,29 @@ +execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + [ + 'options' => '{"template":"{{ name }}","createItemText":"Add Module","fields":[{"field":"name","interface":"text-input","type":"string","width":"half"},{"field":"link","interface":"text-input","type":"string","width":"half"},{"field":"icon","interface":"icon","type":"string","width":"full"}]}' + ], + ['collection' => 'directus_roles', 'field' => 'module_listing'] + )); + + $this->execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + [ + 'options' => '{"template":"{{ group_name }}","createItemText":"Add Group","fields":[{"field":"group_name","width":"full","interface":"text-input","type":"string"},{"field":"collections","interface":"repeater","type":"JSON","options":{"createItemText":"Add Collection","fields":[{"field":"collection","type":"string","interface":"collections","width":"full"}]}}]}' + ], + ['collection' => 'directus_roles', 'field' => 'collection_listing'] + )); + } +} diff --git a/src/core/Directus/Application/Application.php b/src/core/Directus/Application/Application.php index 51c98b0463..6194089d9e 100644 --- a/src/core/Directus/Application/Application.php +++ b/src/core/Directus/Application/Application.php @@ -13,7 +13,7 @@ class Application extends App * * @var string */ - const DIRECTUS_VERSION = '8.1.0'; + const DIRECTUS_VERSION = '8.2.0'; /** * NOT USED diff --git a/src/endpoints/Server.php b/src/endpoints/Server.php index c65086f22b..8a2f0753bc 100644 --- a/src/endpoints/Server.php +++ b/src/endpoints/Server.php @@ -21,9 +21,7 @@ public function __invoke(Application $app) \Directus\create_ping_route($app); $app->get('/projects', [$this, 'projects']); $app->post('/projects', \Directus\Api\Routes\ProjectsCreate::class); - $app->delete('/projects/{name}', \Directus\Api\Routes\ProjectsDelete::class) - ->add(new TableGatewayMiddleware($this->container)); - + $app->delete('/projects/{name}', \Directus\Api\Routes\ProjectsDelete::class); $app->get('/info', [$this, 'getInfo']); } diff --git a/src/helpers/all.php b/src/helpers/all.php index c79e99f589..c797e441fa 100644 --- a/src/helpers/all.php +++ b/src/helpers/all.php @@ -154,6 +154,21 @@ function get_url($path = '') } } +if (!function_exists('get_base_path')) { + /** + * Get Directus' base path + * + * If Directus is running in a folder, this will return the names of the folder + * that Directus is running in, f.e. /directus/public/ + * + * @return string + */ + function get_base_path() + { + return create_uri_from_global()->getBasePath() . '/'; + } +} + if (!function_exists('create_request_from_global')) { /** * Create a Request object from global variables diff --git a/src/helpers/file.php b/src/helpers/file.php index 9642683474..c10f6ffe7a 100644 --- a/src/helpers/file.php +++ b/src/helpers/file.php @@ -262,21 +262,14 @@ function get_thumbnail_url($name,$thumbnail) * * @return string */ - function get_thumbnail_path($name,$thumbnail) + function get_thumbnail_path($name, $thumbnail) { + $basePath = get_base_path(); $projectName = get_api_project_from_request(); - $thumbnailDetail=$thumbnail; + $paramsString = '?key=' . $thumbnail['key']; - $paramsString= '?key='.$thumbnailDetail['key']; - - return sprintf( - '/%s/%s/%s%s', - $projectName, - 'assets', - $name, - $paramsString - ); + return $basePath . $projectName . '/assets/' . $name . $paramsString; } } diff --git a/src/helpers/settings.php b/src/helpers/settings.php index a109f1abe0..45e5e5e7c5 100644 --- a/src/helpers/settings.php +++ b/src/helpers/settings.php @@ -153,22 +153,55 @@ function get_trusted_proxies() */ function get_project_info() { - $settings = get_directus_settings_by_keys(['project_name', 'project_logo','project_color','project_foreground','project_background','default_locale', 'telemetry']); - $settings['project_logo'] = array_get($settings, 'project_logo') ? get_project_logo_data(array_get($settings, 'project_logo')) : null; - $settings['project_foreground'] = array_get($settings, 'project_foreground') ? get_project_logo_data(array_get($settings, 'project_foreground')) : null; - $settings['project_background'] = array_get($settings, 'project_background') ? get_project_logo_data(array_get($settings, 'project_background')) : null; - $settings['telemetry'] = array_get($settings, 'telemetry') && $settings['telemetry'] ? true : false; + $settings = get_directus_settings_by_keys([ + 'project_name', + 'project_logo', + 'project_color', + 'project_foreground', + 'project_background', + 'project_public_note', + 'default_locale', + 'telemetry' + ]); + + // TODO: + // Typecasting of these values should be done the same way as in the `/settings` endpoint. + + $settings['project_logo'] = array_get($settings, 'project_logo') + ? get_file_data(array_get($settings, 'project_logo')) + : null; + + $settings['project_foreground'] = + array_get($settings, 'project_foreground') + ? get_file_data(array_get($settings, 'project_foreground')) + : null; + + $settings['project_background'] = + array_get($settings, 'project_background') + ? get_file_data(array_get($settings, 'project_background')) + : null; + + $settings['project_public_note'] = + array_get($settings, 'project_public_note') + ? array_get($settings, 'project_public_note') + : null; + + $settings['telemetry'] = + array_get($settings, 'telemetry') && $settings['telemetry'] + ? true + : false; + return $settings; } } -if (!function_exists('get_project_logo_data')) { +if (!function_exists('get_file_data')) { /** * @param int $id * * @return array */ - function get_project_logo_data($id) + function get_file_data($id) { /** @var RelationalTableGateway $table */ $table = TableGatewayFactory::create('directus_files', ['acl' => false]); From d73105724eb8d918dfdd5b2e51239aeaac47a133 Mon Sep 17 00:00:00 2001 From: rijkvanzanten Date: Mon, 9 Dec 2019 15:35:10 -0500 Subject: [PATCH 06/11] Alias the `-k` flag to `-N` in the db upgrade module --- src/core/Directus/Console/Modules/DatabaseModule.php | 1 + 1 file changed, 1 insertion(+) diff --git a/src/core/Directus/Console/Modules/DatabaseModule.php b/src/core/Directus/Console/Modules/DatabaseModule.php index f103383c9c..76f57c04d9 100644 --- a/src/core/Directus/Console/Modules/DatabaseModule.php +++ b/src/core/Directus/Console/Modules/DatabaseModule.php @@ -40,6 +40,7 @@ public function cmdUpgrade($args, $extra) foreach ($args as $key => $value) { switch ($key) { case 'N': + case 'k': $project = $value; break; } From c022f4a12c14d8efbcee87f7df4f3f9e73b265f4 Mon Sep 17 00:00:00 2001 From: Rijk van Zanten Date: Wed, 11 Dec 2019 14:07:02 -0500 Subject: [PATCH 07/11] Allow null as value for settings (#1558) Fixes #1557 --- .../20180220023243_create_settings_table.php | 4 +++- .../20191211140300_allow_null_in_settings.php | 14 ++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 migrations/upgrades/20191211140300_allow_null_in_settings.php diff --git a/migrations/install/20180220023243_create_settings_table.php b/migrations/install/20180220023243_create_settings_table.php index a880ce96ab..b11d1c900e 100644 --- a/migrations/install/20180220023243_create_settings_table.php +++ b/migrations/install/20180220023243_create_settings_table.php @@ -15,8 +15,10 @@ public function change() 'limit' => 64, 'null' => false ]); + $table->addColumn('value', 'text', [ - 'default' => null + 'default' => null, + 'null' => true ]); $table->addIndex(['key'], [ diff --git a/migrations/upgrades/20191211140300_allow_null_in_settings.php b/migrations/upgrades/20191211140300_allow_null_in_settings.php new file mode 100644 index 0000000000..82f150c425 --- /dev/null +++ b/migrations/upgrades/20191211140300_allow_null_in_settings.php @@ -0,0 +1,14 @@ +table('directus_settings'); + $settingsTable->changeColumn('value', 'text', [ + 'null' => true + ]); + $settingsTable->save(); + } +} From f977c71117fa08dbc70c8cb3817560f1862e6f42 Mon Sep 17 00:00:00 2001 From: Rijk van Zanten Date: Wed, 11 Dec 2019 14:20:05 -0500 Subject: [PATCH 08/11] Hide the external id field on directus_users (#1560) Fixes #1559 --- .../20180220023248_create_users_table.php | 3 ++- .../20191211141600_hide_externalid.php | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 migrations/upgrades/20191211141600_hide_externalid.php diff --git a/migrations/install/20180220023248_create_users_table.php b/migrations/install/20180220023248_create_users_table.php index 6678c5b994..bb5b7fdd54 100644 --- a/migrations/install/20180220023248_create_users_table.php +++ b/migrations/install/20180220023248_create_users_table.php @@ -532,7 +532,8 @@ public function change() 'interface' => 'text-input', 'locked' => 1, 'readonly' => 1, - 'hidden_detail' => 20 + 'hidden_detail' => 1, + 'hidden_browse' => 1 ], ]; diff --git a/migrations/upgrades/20191211141600_hide_externalid.php b/migrations/upgrades/20191211141600_hide_externalid.php new file mode 100644 index 0000000000..f57534b14f --- /dev/null +++ b/migrations/upgrades/20191211141600_hide_externalid.php @@ -0,0 +1,19 @@ +execute(\Directus\phinx_update( + $this->getAdapter(), + 'directus_fields', + [ + 'hidden_detail' => 1, + 'hidden_browse' => 1 + ], + ['collection' => 'directus_users', 'field' => 'external_id'] + )); + + } +} From 80e4205833f3f13e418e3f63abccc01349708b71 Mon Sep 17 00:00:00 2001 From: rijkvanzanten Date: Thu, 12 Dec 2019 11:51:40 -0500 Subject: [PATCH 09/11] Fix relative url / full url in thumbnails Fixes #1564 --- src/helpers/file.php | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/src/helpers/file.php b/src/helpers/file.php index c10f6ffe7a..016e8d746a 100644 --- a/src/helpers/file.php +++ b/src/helpers/file.php @@ -226,7 +226,7 @@ function get_thumbnails(array $row) } $thumbnailUrl = get_thumbnail_url($row['private_hash'],$thumbnail); - $thumbnailRelativeUrl = get_thumbnail_path($row['private_hash'],$thumbnail); + $thumbnailRelativeUrl = get_thumbnail_path($row['private_hash'], $thumbnail, true); $thumbnails[] = [ 'url' => $thumbnailUrl, 'relative_url' => $thumbnailRelativeUrl, @@ -262,14 +262,21 @@ function get_thumbnail_url($name,$thumbnail) * * @return string */ - function get_thumbnail_path($name, $thumbnail) + function get_thumbnail_path($name, $thumbnail, $addBasePath = false) { - $basePath = get_base_path(); - $projectName = get_api_project_from_request(); + $path = ''; + $projectName = get_api_project_from_request(); $paramsString = '?key=' . $thumbnail['key']; - return $basePath . $projectName . '/assets/' . $name . $paramsString; + $path = $projectName . '/assets/' . $name . $paramsString; + + if ($addBasePath === true) { + $basePath = get_base_path(); + $path = $basePath . $path; + } + + return $path; } } From 877ff431cee39d631646490f05e08e4e2c751ee4 Mon Sep 17 00:00:00 2001 From: rijkvanzanten Date: Thu, 12 Dec 2019 14:46:07 -0500 Subject: [PATCH 10/11] Bump version --- src/core/Directus/Application/Application.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/Directus/Application/Application.php b/src/core/Directus/Application/Application.php index 6194089d9e..12fb2dc0ea 100644 --- a/src/core/Directus/Application/Application.php +++ b/src/core/Directus/Application/Application.php @@ -13,7 +13,7 @@ class Application extends App * * @var string */ - const DIRECTUS_VERSION = '8.2.0'; + const DIRECTUS_VERSION = '8.3.0'; /** * NOT USED From 956df461dd15f83ea1951bd108735d4a3fcc5d89 Mon Sep 17 00:00:00 2001 From: rijkvanzanten Date: Thu, 12 Dec 2019 14:54:59 -0500 Subject: [PATCH 11/11] Fix uploading files through URL embeds Fixes #1552 --- src/core/Directus/Services/FilesServices.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/core/Directus/Services/FilesServices.php b/src/core/Directus/Services/FilesServices.php index 2921d299fc..654f20ecfa 100644 --- a/src/core/Directus/Services/FilesServices.php +++ b/src/core/Directus/Services/FilesServices.php @@ -42,6 +42,7 @@ public function create(array $data, array $params = []) // The filename will be generate automatically if not defined if (is_a_url(ArrayUtils::get($data, 'data'))) { unset($validationConstraints['filename_disk']); + unset($validationConstraints['filename_download']); } $this->validate($data, array_merge(['data' => 'required'], $validationConstraints)); @@ -52,11 +53,12 @@ public function create(array $data, array $params = []) if(get_directus_setting('file_mimetype_whitelist') != null){ validate_file($result['mimeType'],'mimeTypes'); } + if(get_directus_setting('file_max_size') != null){ validate_file($result['size'],'maxSize'); } - $recordData = $this->getSaveData($data,false); + $recordData = $this->getSaveData($data, false); $newFile = $tableGateway->createRecord($recordData, $this->getCRUDParams($params)); @@ -75,12 +77,12 @@ public function getSaveData($data, $isUpdate){ $dataInfo = $files->getLink($data['data']); // Set the URL payload data $data['data'] = ArrayUtils::get($dataInfo, 'data'); - $data['filename_disk'] = ArrayUtils::get($dataInfo, 'filename_disk'); + $data['filename_disk'] = ArrayUtils::get($dataInfo, 'filename'); + $data['filename_download'] = ArrayUtils::get($dataInfo, 'filename'); } else if (array_key_exists('data', $data) && !is_object($data['data'])) { $dataInfo = $files->getDataInfo($data['data']); } - $type = ArrayUtils::get($dataInfo, 'type', ArrayUtils::get($data, 'type')); if (strpos($type, 'embed/') === 0) {