mirror of
https://github.com/directus/directus.git
synced 2026-02-12 07:34:59 -05:00
* Apply aggregation query to dbQuery
* Override fields/sortField when group/aggr is used
* Sanitize incoming group/aggr fields
* Validate for new group/aggr query params
* Document new aggregate/group endpoint
* Add changeset
* Add new system tables
* Add schema, rest/gql resolvers for insights
* Add insights store
* Render insights overview page
* Add dashboard creation flow
* Add not found route
* Show editing grid
* Add panels as extension type
* Render panel selection
* Add edit existing
* Add saving changes
* Add positioning
* Finish resizing
* Start on metric panel
* Auto-expand workspace
* WIP add frappe-chart
* Add functional time-series chart
* Deep watch option changes
* Fix o2m fetch when not grouping
* Allow PK in metric panel
* Add breadcrumb
* Various tweaks and fixes
* Fix metric alignment, only load on options change, Show header
* Add delete panel
* Add updating dashboard
* Swap docs / insights
* Add sort/limit to metric
* Add decimal places, units
* Add label type panel
* Track corner intersaction
* Don't hit the API if there aren't any staged changes
* Remove limit from metric
* Extend resize handlers beyond border
* Fix repositioning on update existing
* Add duplicate panel
* panel duplicate icon
* Increase time series min height
* Improve time series styling
* make panels selectable
* Button styling and fullscren (button only)
* Time series color
* Panel plot display
* Optically align metric
* Add number formatting to metric
* Insights placeholders and defaults
* Fix codemirror placeholder color
* Restart docker containers on docker restart
* Move insights to Vue 3
* Fix val check
* Add button style props
* Fix input/value
* Fix panel init
* Fix buttons on panels
* Fix animation on panel config
* Fix panel location not resetting on cancel
* Add fullscreen / zoom to fit support
* Temp remove transition to prevent browser glitches
* Fix vertical size calculation
* Fix panel editing
* Update params to match fields
* Setup datetime abstraction
* Restructure fn helper
* Add fields support for date functions
* Allow functions in sort/filter
* Fix missing knex passthrough
* Finish date retrieval abstraction for all vendors
* Delete witty-emus-approve.md
* Delete dependabot.yml
* Add renovate.json (#6322)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* New Crowdin updates (#6309)
* New translations en-US.yaml (Japanese)
* New translations en-US.yaml (Japanese)
* New translations en-US.yaml (Arabic)
* New translations en-US.yaml (Arabic)
* New translations en-US.yaml (Arabic)
* New translations en-US.yaml (Arabic)
* fix link (#6339)
* fix(deps): pin dependencies (#6323)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* chore(deps): update dependency globby to v11.0.4 (#6324)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* Add support for `read` hooks on `items` (#6341)
* Add emitter on item read
* Add performance warning to docs
* Make result instead of query the payload
* Redact tokens from logs (#6347)
* Fixed issue that would cause uploads to the root folder of the file library to fail (#6348)
fixes #6310
* Use existing file extension as default (#6349)
* Don't send sensitive data in webhooks (#6350)
Fixes #6246
* Trim val before check
h/t @aidenfoxx
* chore(deps): update mariadb docker tag to v10.6 (#6332)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* chore(deps): update node.js to v16 (#6336)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* chore(deps): update postgres docker tag to v13 (#6338)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* chore(deps): update dependency rollup to v2.52.1 (#6337)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* chore(deps): update dependency vue-router to v4.0.9 (#6327)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* chore(deps): update dependency typescript to v4.3.3 (#6329)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* fix(deps): update dependency ms to v2.1.3 (#6328)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* chore(deps): update dependency marked to v2.1.1 (#6330)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* chore(deps): update fullcalendar monorepo to v5.8.0 (#6331)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* chore(deps): update dependency dotenv to v10 (#6333)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* fix(deps): update dependency chalk to v4 (#6342)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* chore(deps): update dependency fs-extra to v10 (#6334)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* Change cache-control heeaders (#6355)
* chore(deps): update dependency typescript to v4.3.4 (#6357)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* Fixed invalid onDelete constraint for some schemas (#6308)
* Fixed invalid onDelete clause for some schemas
* Ran prettier
* Updated all onDelete statements to be Oracle friendly
Co-authored-by: Aiden Foxx <aiden.foxx@sbab.se>
* Fix import in aggregation
* Fix cancel button on new modal dialog
* Add default icon to new dashboards
* Add information sidebar component
* Don't open sidebar on window resize
* Add distinct options to metrics panel
* Use updated aggregate function type signature
* Reset field value on collection change
* Don't show resize stats on edit click
* Add panel options to header headline on drawer
* Add page-bottom padding to drawers
* Show panel icon in header, fix active state buttons
* Add date range functionality to time-series
* Fix z-index of edit buttons
* Fix header icon color
* Update insights module icon
* Fix datetime formatter, set date range, add padding
* Time series
* tweaks on time series
* format tweaks
* Fix edit dashboard modal
* Add auto-format option
* Fix number formatting w/ decimals
* Add metric conditional color
* Fix defaults rendering in list, add defaults to metric
* Fix decimal points in metrics
* Remove sort
* Tweaks in metrics settings
* Add filters to time series
* Update options for metric
* Time series tweaks
* Allow empty field for metric
* Set label min height to 4
* Add first/last to metric
* Add "move" option, various tweaks
* Upgrade "move to" to "copy to"
* Add white to color preset defaults
* Tweaks
* Use 0 for decimal default
* Use default false for abbreviate
* Fix panel registration
* Show color placeholder, fix edit modal
* Add navigation guard
* Don't fire navguard on subroute
* Show create button on empty dashboards in nav
* Use synced charts
* Undo sync test
* Have metric render 0
* Fix abbreviate decimal places
* Fix min 0 in time-series
* less blocking whitespace
* new metric min width
* new time series min width
* time series style updates
* Fixed typo (#6558)
* Fix auto-fill of directus_files in relational setup (#6555)
Fixes #6487
* v9.0.0-rc.82
* Update changelog.md
* Add limit options for deleteMany files (#6561)
* Changed filesize to bigint for large files
* Update api/src/database/migrations/20210626A-change-filesize-bigint.ts
* add `limit -1` for deleteMany files options from #6560
Co-authored-by: Rijk van Zanten <rijkvanzanten@me.com>
* Fix cleaning order
* update dependency ts-node-dev to v1.1.7 (#6564)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* Fix order of form group filter (#6566)
Fixes #6557
* New Crowdin updates (#6554)
* New translations en-US.yaml (Bulgarian)
* Update source file en-US.yaml
* v9.0.0-rc.83
* Update the required Node version to 12.20.0 (#6578)
* update dependency rollup to v2.52.4 (#6572)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* Add skip admin init flag (#6576)
* adds skipAdminInit flag to bootstrap
* checks for skipAdminInit flag
* update docs for skipAdminInit
* Fix extension loading on windows (#6579)
Javascript import syntax uses URLs instead of paths, so we have to
normalize the extension paths to forward slashes when importing them
inside the virtual entrypoints.
Fixes #6550
* New Crowdin updates (#6575)
* New translations en-US.yaml (Hebrew)
* New translations en-US.yaml (Hebrew)
* insights time series min size
* Only ask for are you sure when edits are made
* Add cancel confirmation
* Add system collections to pane dropdown
* Disable zoom to fit when enabling edit mode
* Render browser popup on reload
* Fix padding in TV mode
* Fix box
* Add show X/Y axis options
* Default to 0 decimals
* Use configured decimals in Y axis labels
* Fix build
* Aggregate resolvers added to GraphQL options (#7373)
* Don't use tags interface for CSV filter (#7258)
Fixes #6778
* Rely on `RETURNING` when possible (#7259)
* WIP use returning clause instead of max from id
* Use returning where applicable, fallback to fetch
Fixes #6279
* update dependency p-queue to v7 (#7255)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* update dependency @vitejs/plugin-vue to v1.4.0 (#7263)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* Move p-queue to app dev dependencies (#7273)
* Log error message when registering app extension fails (#7274)
* update dependency rollup to v2.56.1 (#7269)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* update dependency vue-router to v4.0.11 (#7272)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* update dependency ts-node to v10.2.0 (#7271)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* Only loads app extensions if SERVE_APP is true (#7275)
This also ensures API/App only load their respective extensions in dev.
* Fix gitignore file in extension templates being deleted when publishing (#7279)
* New Crowdin updates (#7260)
* New translations en-US.yaml (Spanish)
* New translations en-US.yaml (Spanish)
* New translations en-US.yaml (Russian)
* New translations en-US.yaml (Russian)
* New translations en-US.yaml (Russian)
* New translations en-US.yaml (Russian)
* update typescript-eslint monorepo to v4.29.1 (#7283)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* Only treat `tinyint(1)` and `tinyint(0)` as booleans (#7287)
* added an if catch for tinyint(1) and tinyint(0)
* made suggested changes toLowerCase()
* update dependency @vue/compiler-sfc to v3.2.0 (#7288)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* update dependency vue to v3.2.0 (#7289)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* Handle JSON in labels display (#7292)
Fixes #7278
* update dependency pinia to v2.0.0-rc.3 (#7055)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* update vue monorepo to v3.2.1 (#7293)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* Flush caches on server (re)start (#7294)
* v9.0.0-rc.89
* Update package-lock
* Update release script
To workaround breaking change in npm patch 🎉
* Update changelog
* update dependency pinia to v2.0.0-rc.4 (#7297)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* update dependency rollup to v2.56.2 (#7303)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* Fix HTTP method for collections.createMany in SDK (#7304)
* Fix HTTP method for collections.createMany in SDK
* Post collections in data body
Co-authored-by: rijkvanzanten <rijkvanzanten@me.com>
* Add perm check for sqlite, upload, extensions dirs (#7310)
Co-authored-by: Rijk van Zanten <rijkvanzanten@me.com>
* update dependency eslint-plugin-vue to v7.16.0 (#7300)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* Fix uuid resolving in SQLite (#7312)
Fixes #7306
* Clear the file payload after file upload (#7315)
Fixes #7305
* Improve type checking
* Mention TELEMETRY environment variable in docs (#7317)
* Mention TELEMETRY environment variable in docs
* Add clarification
Co-authored-by: rijkvanzanten <rijkvanzanten@me.com>
* Import access from fs-extra instead of fs/promises
* Resolve sorting in list-o2m-tree-view on dnd
* Fix graphql GET request cache query extraction (#7319)
Fixes #7298
* Check for related collection before creation relation (#7323)
Fixes #7302
* Fix colors on different types (#7322)
Co-authored-by: Rijk van Zanten <rijkvanzanten@me.com>
* group is working on aggregate resolver
* Check for non-existing parent pk records (#7331)
Fixes #7330
* Schema field types are not translated in the app (#7327)
* Fix field type label translations
* Use translate-object-values util
Co-authored-by: rijkvanzanten <rijkvanzanten@me.com>
* Update release script
* Add import ref for TS
* Tweak, hopefully fix release flow
* getAggregateQuery
* clean up payload
Co-authored-by: Rijk van Zanten <rijkvanzanten@me.com>
* Treat alias-only fields properly
* Add missing translations (#7358)
* v9.0.0-rc.90
* Update changelog.md
* update dependency nanoid to v3.1.24 (#7365)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* update dependency supertest to v6.1.5 (#7360)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* update vue monorepo to v3.2.2 (#7355)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* filters working avg{id} format with number fields
* Fix english string after #7358 (#7371)
Fixed wrong string in en-US after #7358 PR
* group field working
* update dependency nanoid to v3.1.25 (#7375)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* update dependency directory-tree to v2.3.0 (#7376)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* Export Collection button now shows collection name not table name (#7379)
* export collection button to uses name not db name
* removed unused var
* fixed for review
* computed collectionName
* Add support for Geometry type, add Map Layout & Interface (#5684)
* Added map layout
* Cleanup and bug fixes
* Removed package-lock
* Cleanup and fixes
* Small fix
* Added back package-lock
* Saved camera, autofitting option, bug fixes
* Refactor and ui improvements
* Improvements
* Added seled mode
* Removed unused dependency
* Changed selection behaviour, cleanup.
* update import and dependencies
* make custom style into drawer
* remove unused imports
* use lodash functions
* add popups
* allow header to become small
* reorganize settings
* add styling to popup
* change default template
* add projection option
* add basic map interface
* finish simple map
* add mapbox style
* support more mapbox layouts
* add api key option
* add mapbox backgrounds to layout
* warn when no api key is set
* fix for latest version
* Improved map layout and interface, bug fixes, refactoring.
.
.
* Added postgis geometry format, added marker icon shadow
* Made map buttons bigger and their icons thinner. Added transition to header bar.
* Bug fixes and error handling in map interface.
* Moved box-select control out of the map component. Removed material icons sprite and use addImage for marker support.
* Handle MultiGeometry -> Geometry interface error.
* Removed hardcoded styles. Added migrations for basemap column. Lots of refactoring.
Removed hardcoded styles. Added migrations for basemap column. Lots of refactoring.
* Fixed style reloading error. Added translations.
* Moved worker code to lib.
* Removed worker code. Prevent Mapbox from removing access_token from the URL.
* Refactoring.
* Change basemap selection to in-map dropdown for layout and interface.
* Touchscreen selection support and small fixes.
* Small change.
* Fixed unused imports.
* Added support for PostgreSQL identity column
* Renamed migration. Added crs translation.
* Only show fields using the map interface in the map layout.
* Removed logging.
* Reverted Dockerfile change.
* Improved crs support.
* Fixed translations.
* Check for schema identity before updating it.
* Fixed popup not updating on feature hover.
* Added feature hover styling. Fixed layer customization input. Added out of bounds error handling.
* Added geometry type and support for database native geometries.
* Fixed linting.
* Fixed layout.
* Fixed layout.
* Actually fixed linting
* Full support for native geometries
Fixed basemap input
Improved feature popup on hover
Locked interfaced support
* Fixed geometryType option not updating
* Bug fixes in interface
* Fixed crash when empty basemap settings. Fixed fitBounds option not updating.
* Added back storage type option. Improved interface behaviour.
* Dropped wkb because of vendor inconsistency with binary data
* Updated layout to match new geometry type. Fixed geojson payload transform.
* Added missing geometry_format attributes to local types.
* Fixed typos & refactoring
* Removed dependency on proj4
* Fix error when empty map interface options
* Set geometry SRID to 4326 when inserting into the database
* Add support for selectMode
* Fix error on initial source load
* Added geocoder, use GeoJSON for api i/o, removed geometry_format option, refactoring
* Added geometry intersects filter. Created geometry helper class.
* Fix error when null geometryOptions, added mapbox_key setting.
* Moved all geometry parsing/serializing into processGeometries in `payload.ts`. Fixed type errors.
* Migrate to Vue 3
* Use wellknown instead of wkx
* Fixed basemap selection.
* Added available operator for geometry type
* Added nintersects filter, fixed map interface for filter input
* Added intersects_bbox filter & bug fixes.
* Fixed icons rendering
* Fixed cursor icon in select mode
* Added geometry aggregate function
* Fixed geometry processing bug when imported from relational field.
* Fixed error with geocoder instanciation
* Removed @types/maplibre-gl dependency
* Removed fitViewToData options
* Merge remote-tracking branch 'upstream/main' into map-layout
* Fixed style and geometryType in map interface options
* Fixed style change on map interface.
* Improved fitViewToData behaviour
* Fixed type imports and previous merge conflict
* Fixed linting
* Added available operators
* Fix and merge migrations
* Remove outdated p-queue dep
* Fix get-schema column extract
* Replace pg with postgis for local debugging
* Re-add missing import
* Add mapbox as a basemap when key exists
* Remove unused tz flag
* Process delta in payloadservice
* Set default map, add limit number styling
* Default display template to just PK
* Tweak styling of error dialog
* Fix method usage in helpers
* Move sdo_geo to oracle section
* Remove extensions from ts config exclude
* Move geo types to shared, remove _Geometry
* Remove unused type
* Tiny Tweaks
* Remove fit to bounds option in favor of on
* Validate incoming intersects query
* Deepmap filter values
* Add GraphQL support
* No defaultValue for geometryType
* Resolve c
* Fix translations
Co-authored-by: Nitwel <nitwel@arcor.de>
Co-authored-by: Rijk van Zanten <rijkvanzanten@me.com>
* New Crowdin updates (#7359)
* New translations en-US.yaml (Estonian)
* New translations en-US.yaml (Ukrainian)
* New translations en-US.yaml (Norwegian)
* New translations en-US.yaml (Polish)
* New translations en-US.yaml (Portuguese)
* New translations en-US.yaml (Russian)
* New translations en-US.yaml (Serbian (Cyrillic))
* New translations en-US.yaml (Swedish)
* New translations en-US.yaml (Turkish)
* New translations en-US.yaml (Chinese Traditional)
* New translations en-US.yaml (Portuguese, Brazilian)
* New translations en-US.yaml (Indonesian)
* New translations en-US.yaml (Spanish, Chile)
* New translations en-US.yaml (Thai)
* New translations en-US.yaml (Hindi)
* New translations en-US.yaml (Malay)
* New translations en-US.yaml (Serbian (Latin))
* New translations en-US.yaml (Dutch)
* New translations en-US.yaml (Italian)
* New translations en-US.yaml (Afrikaans)
* New translations en-US.yaml (Lithuanian)
* New translations en-US.yaml (Spanish, Latin America)
* New translations en-US.yaml (Slovenian)
* New translations en-US.yaml (Vietnamese)
* New translations en-US.yaml (Chinese Simplified)
* New translations en-US.yaml (Bulgarian)
* New translations en-US.yaml (Romanian)
* New translations en-US.yaml (French)
* New translations en-US.yaml (Spanish)
* New translations en-US.yaml (Arabic)
* New translations en-US.yaml (Georgian)
* New translations en-US.yaml (Catalan)
* New translations en-US.yaml (Czech)
* New translations en-US.yaml (Danish)
* New translations en-US.yaml (German)
* New translations en-US.yaml (Greek)
* New translations en-US.yaml (Finnish)
* New translations en-US.yaml (Hebrew)
* New translations en-US.yaml (Hungarian)
* New translations en-US.yaml (Japanese)
* Update source file en-US.yaml
* New translations en-US.yaml (Italian)
* New translations en-US.yaml (Slovenian)
* New translations en-US.yaml (Estonian)
* New translations en-US.yaml (Estonian)
* New translations en-US.yaml (Sinhala)
* New translations en-US.yaml (Russian)
* New translations en-US.yaml (Russian)
* New translations en-US.yaml (Bulgarian)
* Update source file en-US.yaml
* New translations en-US.yaml (Estonian)
* New translations en-US.yaml (Norwegian)
* New translations en-US.yaml (Polish)
* New translations en-US.yaml (Portuguese)
* New translations en-US.yaml (Russian)
* New translations en-US.yaml (Swedish)
* New translations en-US.yaml (Turkish)
* New translations en-US.yaml (Portuguese, Brazilian)
* New translations en-US.yaml (Spanish, Chile)
* New translations en-US.yaml (Thai)
* New translations en-US.yaml (Serbian (Latin))
* New translations en-US.yaml (Dutch)
* New translations en-US.yaml (Lithuanian)
* New translations en-US.yaml (Spanish, Latin America)
* New translations en-US.yaml (Vietnamese)
* New translations en-US.yaml (Chinese Simplified)
* New translations en-US.yaml (Bulgarian)
* New translations en-US.yaml (French)
* New translations en-US.yaml (Spanish)
* New translations en-US.yaml (Arabic)
* New translations en-US.yaml (German)
* New translations en-US.yaml (Finnish)
* New translations en-US.yaml (Hungarian)
* update dependency directory-tree to v2.3.1 (#7380)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* pin dependencies (#7384)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* update dependency macos-release to v3 (#7381)
* update dependency macos-release to v3
* Update package-lock
Co-authored-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: rijkvanzanten <rijkvanzanten@me.com>
* New Crowdin updates (#7386)
* Update source file en-US.yaml
* New translations en-US.yaml (Estonian)
* New translations en-US.yaml (Polish)
* New translations en-US.yaml (Portuguese)
* New translations en-US.yaml (Russian)
* New translations en-US.yaml (Swedish)
* New translations en-US.yaml (Turkish)
* New translations en-US.yaml (Chinese Traditional)
* New translations en-US.yaml (Portuguese, Brazilian)
* New translations en-US.yaml (Indonesian)
* New translations en-US.yaml (Spanish, Chile)
* New translations en-US.yaml (Thai)
* New translations en-US.yaml (Serbian (Latin))
* New translations en-US.yaml (Dutch)
* New translations en-US.yaml (Italian)
* New translations en-US.yaml (Lithuanian)
* New translations en-US.yaml (Spanish, Latin America)
* New translations en-US.yaml (Slovenian)
* New translations en-US.yaml (Vietnamese)
* New translations en-US.yaml (Chinese Simplified)
* New translations en-US.yaml (Bulgarian)
* New translations en-US.yaml (French)
* New translations en-US.yaml (Spanish)
* New translations en-US.yaml (Arabic)
* New translations en-US.yaml (German)
* New translations en-US.yaml (Finnish)
* New translations en-US.yaml (Hungarian)
* Revert "update dependency macos-release to v3 (#7381)" (#7389)
This reverts commit ca111a80cb.
* update dependency npm to v7.20.6 (#7387)
Co-authored-by: Renovate Bot <bot@renovateapp.com>
* Fix flat lock number
* Small tweaks, fix type bug
Co-authored-by: Rijk van Zanten <rijkvanzanten@me.com>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: Nicola Krumschmidt <nicola.krumschmidt@freenet.de>
Co-authored-by: Pascal Jufer <paescuj@users.noreply.github.com>
Co-authored-by: Adrian Dimitrov <dimitrov.adrian@gmail.com>
Co-authored-by: Oreille <33065839+Oreilles@users.noreply.github.com>
Co-authored-by: Nitwel <nitwel@arcor.de>
* Fix merge quirk
* Add support for aliasing fields (#7419)
* Don't double split csv values
* Still join them on create tho
* Add support for `alias` query param
* Support aliases in wildcards
* Alias Support Within GraphQL (#7410)
* graphQL support for aliases
* moved aliases to its own function parseAliases
* Tweak types
Co-authored-by: rijkvanzanten <rijkvanzanten@me.com>
* Fix field resolution on alias usage
Fixes #5551
* Add `*_func` resolvers for date/time/datetime/timestamp fields
* graphQL Enum for groupby (#7445)
Co-authored-by: Rijk van Zanten <rijkvanzanten@me.com>
Co-authored-by: Rijk van Zanten <rijkvanzanten@me.com>
* Docs for Aggregation + Group By + Aliases (#7436)
* aggregation docs for graphql
* aliases
* added REST examples
* rest queries
* logo max size
* Recreate package-lock
* Update types/structure
* Fix childNode fetching
* Fix grouping
* Fix time-series
* Fix metric panel
* Add date func support in filter input graphql
* List panel (#8129)
* Merge branch 'main' of https://github.com/directus/directus into list-panel
* list showing mostly styled.
* Add missing options, cleanup
* Add editing to list panel type
* Tweak sizing
Co-authored-by: jaycammarano <jay.cammarano@gmail.com>
* Add no-data notice to list panel
* Camelcasify show_header
* Add cmd+s shortcut
* Tweak sizing, fix translation key
* Update docs
* Add multi-group support to GraphQL
* Align syntax of interfaces & panels
* Tweak min-size of label panel
* Fix linter warnings/errors
* Fix totally unrelated issue
But I'm here now anyways, so might as well
Co-authored-by: Ben Haynes <ben@rngr.org>
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
Co-authored-by: Renovate Bot <bot@renovateapp.com>
Co-authored-by: Geert Ijewski <51948919+geertijewski@users.noreply.github.com>
Co-authored-by: Thijs-Jan <13321277+MoltenCoffee@users.noreply.github.com>
Co-authored-by: Nacho García <hello@nachogarcia.dev>
Co-authored-by: Aiden Foxx <aiden.foxx.mail@gmail.com>
Co-authored-by: Aiden Foxx <aiden.foxx@sbab.se>
Co-authored-by: Oreille <33065839+Oreilles@users.noreply.github.com>
Co-authored-by: Zorin Sergey <36981278+Enhed@users.noreply.github.com>
Co-authored-by: Nicola Krumschmidt <nicola.krumschmidt@freenet.de>
Co-authored-by: Tommaso Bartolucci <tommasobartolucci11@gmail.com>
Co-authored-by: Jay Cammarano <67079013+jaycammarano@users.noreply.github.com>
Co-authored-by: Pascal Jufer <paescuj@users.noreply.github.com>
Co-authored-by: Adrian Dimitrov <dimitrov.adrian@gmail.com>
Co-authored-by: Nitwel <nitwel@arcor.de>
Co-authored-by: jaycammarano <jay.cammarano@gmail.com>
318 lines
9.4 KiB
TypeScript
318 lines
9.4 KiB
TypeScript
import { Knex } from 'knex';
|
|
import { cloneDeep, merge, uniq, uniqWith, flatten, isNil } from 'lodash';
|
|
import getDatabase from '../database';
|
|
import { ForbiddenException } from '../exceptions';
|
|
import { FailedValidationException } from '@directus/shared/exceptions';
|
|
import { validatePayload, parseFilter } from '@directus/shared/utils';
|
|
import { Accountability } from '@directus/shared/types';
|
|
import {
|
|
AbstractServiceOptions,
|
|
AST,
|
|
FieldNode,
|
|
Item,
|
|
NestedCollectionNode,
|
|
Permission,
|
|
PermissionsAction,
|
|
PrimaryKey,
|
|
Query,
|
|
SchemaOverview,
|
|
Aggregate,
|
|
} from '../types';
|
|
import { ItemsService } from './items';
|
|
import { PayloadService } from './payload';
|
|
|
|
export class AuthorizationService {
|
|
knex: Knex;
|
|
accountability: Accountability | null;
|
|
payloadService: PayloadService;
|
|
schema: SchemaOverview;
|
|
|
|
constructor(options: AbstractServiceOptions) {
|
|
this.knex = options.knex || getDatabase();
|
|
this.accountability = options.accountability || null;
|
|
this.schema = options.schema;
|
|
this.payloadService = new PayloadService('directus_permissions', {
|
|
knex: this.knex,
|
|
schema: this.schema,
|
|
});
|
|
}
|
|
|
|
async processAST(ast: AST, action: PermissionsAction = 'read'): Promise<AST> {
|
|
const collectionsRequested = getCollectionsFromAST(ast);
|
|
|
|
const permissionsForCollections = uniqWith(
|
|
this.schema.permissions.filter((permission) => {
|
|
return (
|
|
permission.action === action &&
|
|
collectionsRequested.map(({ collection }) => collection).includes(permission.collection)
|
|
);
|
|
}),
|
|
(curr, prev) => curr.collection === prev.collection && curr.action === prev.action && curr.role === prev.role
|
|
);
|
|
|
|
// If the permissions don't match the collections, you don't have permission to read all of them
|
|
const uniqueCollectionsRequestedCount = uniq(collectionsRequested.map(({ collection }) => collection)).length;
|
|
|
|
if (uniqueCollectionsRequestedCount !== permissionsForCollections.length) {
|
|
throw new ForbiddenException();
|
|
}
|
|
|
|
validateFields(ast);
|
|
applyFilters(ast, this.accountability);
|
|
|
|
return ast;
|
|
|
|
/**
|
|
* Traverses the AST and returns an array of all collections that are being fetched
|
|
*/
|
|
function getCollectionsFromAST(ast: AST | NestedCollectionNode): { collection: string; field: string }[] {
|
|
const collections = [];
|
|
|
|
if (ast.type === 'm2a') {
|
|
collections.push(...ast.names.map((name) => ({ collection: name, field: ast.fieldKey })));
|
|
|
|
for (const children of Object.values(ast.children)) {
|
|
for (const nestedNode of children) {
|
|
if (nestedNode.type !== 'field') {
|
|
collections.push(...getCollectionsFromAST(nestedNode));
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
collections.push({
|
|
collection: ast.name,
|
|
field: ast.type === 'root' ? null : ast.fieldKey,
|
|
});
|
|
|
|
for (const nestedNode of ast.children) {
|
|
if (nestedNode.type !== 'field') {
|
|
collections.push(...getCollectionsFromAST(nestedNode));
|
|
}
|
|
}
|
|
}
|
|
|
|
return collections as { collection: string; field: string }[];
|
|
}
|
|
|
|
function validateFields(ast: AST | NestedCollectionNode | FieldNode) {
|
|
if (ast.type !== 'field') {
|
|
if (ast.type === 'm2a') {
|
|
for (const [collection, children] of Object.entries(ast.children)) {
|
|
checkFields(collection, children, ast.query?.[collection]?.aggregate);
|
|
}
|
|
} else {
|
|
checkFields(ast.name, ast.children, ast.query?.aggregate);
|
|
}
|
|
}
|
|
|
|
function checkFields(collection: string, children: (NestedCollectionNode | FieldNode)[], aggregate?: Aggregate) {
|
|
// We check the availability of the permissions in the step before this is run
|
|
const permissions = permissionsForCollections.find((permission) => permission.collection === collection)!;
|
|
const allowedFields = permissions.fields || [];
|
|
|
|
if (aggregate && allowedFields.includes('*') === false) {
|
|
for (const aliasMap of Object.values(aggregate)) {
|
|
if (!aliasMap) continue;
|
|
|
|
for (const column of Object.keys(aliasMap)) {
|
|
if (allowedFields.includes(column) === false) throw new ForbiddenException();
|
|
}
|
|
}
|
|
}
|
|
|
|
for (const childNode of children) {
|
|
if (childNode.type !== 'field') {
|
|
validateFields(childNode);
|
|
continue;
|
|
}
|
|
|
|
if (allowedFields.includes('*')) continue;
|
|
|
|
const fieldKey = childNode.name;
|
|
|
|
if (allowedFields.includes(fieldKey) === false) {
|
|
throw new ForbiddenException();
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function applyFilters(
|
|
ast: AST | NestedCollectionNode | FieldNode,
|
|
accountability: Accountability | null
|
|
): AST | NestedCollectionNode | FieldNode {
|
|
if (ast.type !== 'field') {
|
|
if (ast.type === 'm2a') {
|
|
const collections = Object.keys(ast.children);
|
|
|
|
for (const collection of collections) {
|
|
updateFilterQuery(collection, ast.query[collection]);
|
|
}
|
|
|
|
for (const [collection, children] of Object.entries(ast.children)) {
|
|
ast.children[collection] = children.map((child) => applyFilters(child, accountability)) as (
|
|
| NestedCollectionNode
|
|
| FieldNode
|
|
)[];
|
|
}
|
|
} else {
|
|
const collection = ast.name;
|
|
|
|
updateFilterQuery(collection, ast.query);
|
|
|
|
ast.children = ast.children.map((child) => applyFilters(child, accountability)) as (
|
|
| NestedCollectionNode
|
|
| FieldNode
|
|
)[];
|
|
}
|
|
}
|
|
|
|
return ast;
|
|
|
|
function updateFilterQuery(collection: string, query: Query) {
|
|
// We check the availability of the permissions in the step before this is run
|
|
const permissions = permissionsForCollections.find((permission) => permission.collection === collection)!;
|
|
|
|
const parsedPermissions = parseFilter(permissions.permissions, accountability);
|
|
|
|
if (!query.filter || Object.keys(query.filter).length === 0) {
|
|
query.filter = { _and: [] };
|
|
} else {
|
|
query.filter = { _and: [query.filter] };
|
|
}
|
|
|
|
if (parsedPermissions && Object.keys(parsedPermissions).length > 0) {
|
|
query.filter._and.push(parsedPermissions);
|
|
}
|
|
|
|
if (query.filter._and.length === 0) delete query.filter._and;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Checks if the provided payload matches the configured permissions, and adds the presets to the payload.
|
|
*/
|
|
validatePayload(action: PermissionsAction, collection: string, data: Partial<Item>): Promise<Partial<Item>> {
|
|
const payload = cloneDeep(data);
|
|
|
|
let permission: Permission | undefined;
|
|
|
|
if (this.accountability?.admin === true) {
|
|
permission = {
|
|
id: 0,
|
|
role: this.accountability?.role,
|
|
collection,
|
|
action,
|
|
permissions: {},
|
|
validation: {},
|
|
fields: ['*'],
|
|
presets: {},
|
|
};
|
|
} else {
|
|
permission = this.schema.permissions.find((permission) => {
|
|
return permission.collection === collection && permission.action === action;
|
|
});
|
|
|
|
if (!permission) throw new ForbiddenException();
|
|
|
|
// Check if you have permission to access the fields you're trying to access
|
|
|
|
const allowedFields = permission.fields || [];
|
|
|
|
if (allowedFields.includes('*') === false) {
|
|
const keysInData = Object.keys(payload);
|
|
const invalidKeys = keysInData.filter((fieldKey) => allowedFields.includes(fieldKey) === false);
|
|
|
|
if (invalidKeys.length > 0) {
|
|
throw new ForbiddenException();
|
|
}
|
|
}
|
|
}
|
|
|
|
const preset = parseFilter(permission.presets || {}, this.accountability);
|
|
|
|
const payloadWithPresets = merge({}, preset, payload);
|
|
|
|
const hasValidationRules =
|
|
isNil(permission.validation) === false && Object.keys(permission.validation ?? {}).length > 0;
|
|
|
|
const requiredColumns: SchemaOverview['collections'][string]['fields'][string][] = [];
|
|
|
|
for (const field of Object.values(this.schema.collections[collection].fields)) {
|
|
const specials = field?.special ?? [];
|
|
|
|
const hasGenerateSpecial = ['uuid', 'date-created', 'role-created', 'user-created'].some((name) =>
|
|
specials.includes(name)
|
|
);
|
|
|
|
const notNullable = field.nullable === false && hasGenerateSpecial === false;
|
|
|
|
if (notNullable) {
|
|
requiredColumns.push(field);
|
|
}
|
|
}
|
|
|
|
if (hasValidationRules === false && requiredColumns.length === 0) {
|
|
return payloadWithPresets;
|
|
}
|
|
|
|
if (requiredColumns.length > 0) {
|
|
permission.validation = hasValidationRules ? { _and: [permission.validation] } : { _and: [] };
|
|
|
|
for (const field of requiredColumns) {
|
|
if (action === 'create' && field.defaultValue === null) {
|
|
permission.validation._and.push({
|
|
[field.field]: {
|
|
_submitted: true,
|
|
},
|
|
});
|
|
}
|
|
|
|
permission.validation._and.push({
|
|
[field.field]: {
|
|
_nnull: true,
|
|
},
|
|
});
|
|
}
|
|
}
|
|
|
|
const validationErrors: FailedValidationException[] = [];
|
|
|
|
validationErrors.push(
|
|
...flatten(
|
|
validatePayload(parseFilter(permission.validation!, this.accountability), payloadWithPresets).map((error) =>
|
|
error.details.map((details) => new FailedValidationException(details))
|
|
)
|
|
)
|
|
);
|
|
|
|
if (validationErrors.length > 0) throw validationErrors;
|
|
|
|
return payloadWithPresets;
|
|
}
|
|
|
|
async checkAccess(action: PermissionsAction, collection: string, pk: PrimaryKey | PrimaryKey[]): Promise<void> {
|
|
if (this.accountability?.admin === true) return;
|
|
|
|
const itemsService = new ItemsService(collection, {
|
|
accountability: this.accountability,
|
|
knex: this.knex,
|
|
schema: this.schema,
|
|
});
|
|
|
|
const query: Query = {
|
|
fields: ['*'],
|
|
};
|
|
|
|
if (Array.isArray(pk)) {
|
|
const result = await itemsService.readMany(pk, { ...query, limit: pk.length }, { permissionsAction: action });
|
|
if (!result) throw new ForbiddenException();
|
|
if (result.length !== pk.length) throw new ForbiddenException();
|
|
} else {
|
|
const result = await itemsService.readOne(pk, query, { permissionsAction: action });
|
|
if (!result) throw new ForbiddenException();
|
|
}
|
|
}
|
|
}
|