Add ability to share items with people outside the platform (#10663)

* Add directus_shares

* Don't check for usage limit on refresh

* Add all endpoints to the shares controller

* Move route `/auth/shared` to `/shared/auth`

* Add password protection

* Add `share` action in permissions

* Add `shares/:pk/info`

* Start on shared-view

* Add basic styling for full shared view

* Fixed migrations

* Add inline style for shared view

* Allow title override

* Finish /info endpoint for shares

* Add basic UUID validation to share/info endpont

* Add UUID validation to other routes

* Add not found state

* Cleanup /extract/finish share login endpoint

* Cleanup auth

* Added `share_start` and `share_end`

* Add share sidebar details.

* Allow share permissions configuration

* Hide the `new_share` button for unauthorized users

* Fix uses_left displayed value

* Show expired / upcoming shares

* Improved expired/upcoming styling

* Fixed share login query

* Fix check-ip and get-permissions middlewares behaviour when role is null

* Simplify cache key

* Fix typescript linting issues

* Handle app auth flow for shared page

* Fixed /users/me response

* Show when user is authenticated

* Try showing item drawer in shared page

* Improved shared card styling

* Add shares permissions and change share card styling

* Pull in schema/permissions on share

* Create getPermissionForShare file

* Change getPermissionsForShare signature

* Render form + item on share after auth

* Finalize public front end

* Handle fake o2m field in applyQuery

* [WIP]

* New translations en-US.yaml (Bulgarian) (#10585)

* smaller label height (#10587)

* Update to the latest Material Icons (#10573)

The icons are based on https://fonts.google.com/icons

* New translations en-US.yaml (Arabic) (#10593)

* New translations en-US.yaml (Arabic) (#10594)

* New translations en-US.yaml (Portuguese, Brazilian) (#10604)

* New translations en-US.yaml (French) (#10605)

* New translations en-US.yaml (Italian) (#10613)

* fix M2A list not updating (#10617)

* Fix filters

* Add admin filter on m2o role selection

* Add admin filter on m2o role selection

* Add o2m permissions traversing

* Finish relational tree permissions generation

* Handle implicit a2o relation

* Update implicit relation regex

* Fix regex

* Fix implicitRelation unnesting for new regex

* Fix implicitRelation length check

* Rename m2a to a2o internally

* Add auto-gen permissions for a2o

* [WIP] Improve share UX

* Add ctx menu options

* Add share dialog

* Add email notifications

* Tweak endpoint

* Tweak file interface disabled state

* Add nicer invalid state to password input

* Dont return info for expired/upcoming shares

* Tweak disabled state for relational interfaces

* Fix share button for non admin roles

* Show/hide edit/delete based on permissions to shares

* Fix imports of mutationtype

* Resolve (my own) suggestions

* Fix migration for ms sql

* Resolve last suggestion

Co-authored-by: Oreilles <oreilles.github@nitoref.io>
Co-authored-by: Oreilles <33065839+oreilles@users.noreply.github.com>
Co-authored-by: Ben Haynes <ben@rngr.org>
Co-authored-by: Thien Nguyen <72242664+tatthien@users.noreply.github.com>
Co-authored-by: Azri Kahar <42867097+azrikahar@users.noreply.github.com>
This commit is contained in:
Rijk van Zanten
2021-12-23 18:51:59 -05:00
committed by GitHub
parent d947c4f962
commit dbf35a1736
89 changed files with 2422 additions and 376 deletions

View File

@@ -0,0 +1,38 @@
import { Knex } from 'knex';
export async function up(knex: Knex): Promise<void> {
await knex.schema.createTable('directus_shares', (table) => {
table.uuid('id').primary();
table.string('name');
table.string('collection', 64).references('collection').inTable('directus_collections').onDelete('CASCADE');
table.string('item');
table.uuid('role').references('id').inTable('directus_roles').onDelete('CASCADE');
table.string('password');
table.uuid('user_created').references('id').inTable('directus_users').onDelete('SET NULL');
table.timestamp('date_created').defaultTo(knex.fn.now());
table.timestamp('date_start');
table.timestamp('date_end');
table.integer('times_used').defaultTo(0);
table.integer('max_uses');
});
await knex.schema.alterTable('directus_sessions', (table) => {
table.dropColumn('data');
});
await knex.schema.alterTable('directus_sessions', (table) => {
table.uuid('user').nullable().alter();
table.uuid('share').references('id').inTable('directus_shares').onDelete('CASCADE');
});
}
export async function down(knex: Knex): Promise<void> {
await knex.schema.alterTable('directus_sessions', (table) => {
table.uuid('user').notNullable().alter();
table.json('data');
table.dropForeign('share');
table.dropColumn('share');
});
await knex.schema.dropTable('directus_shares');
}

View File

@@ -46,7 +46,7 @@ export default async function runAST(
const knex = options?.knex || getDatabase();
if (ast.type === 'm2a') {
if (ast.type === 'a2o') {
const results: { [collection: string]: null | Item | Item[] } = {};
for (const collection of ast.names) {
@@ -141,7 +141,7 @@ async function parseCurrentLevel(
columnsToSelectInternal.push(child.fieldKey);
}
if (child.type === 'm2a') {
if (child.type === 'a2o') {
columnsToSelectInternal.push(child.relation.field);
columnsToSelectInternal.push(child.relation.meta!.one_collection_field!);
}
@@ -263,7 +263,7 @@ function applyParentFilters(
} else {
nestedNode.query.union = [foreignField, foreignIds];
}
} else if (nestedNode.type === 'm2a') {
} else if (nestedNode.type === 'a2o') {
const keysPerCollection: { [collection: string]: (string | number)[] } = {};
for (const parentItem of parentItems) {
@@ -346,7 +346,7 @@ function mergeWithParentItems(
parentItem[nestedNode.fieldKey] = itemChildren.length > 0 ? itemChildren : [];
}
} else if (nestedNode.type === 'm2a') {
} else if (nestedNode.type === 'a2o') {
for (const parentItem of parentItems) {
if (!nestedNode.relation.meta?.one_collection_field) {
parentItem[nestedNode.fieldKey] = null;
@@ -381,7 +381,7 @@ function removeTemporaryFields(
const rawItems = cloneDeep(toArray(rawItem));
const items: Item[] = [];
if (ast.type === 'm2a') {
if (ast.type === 'a2o') {
const fields: Record<string, string[]> = {};
const nestedCollectionNodes: Record<string, NestedCollectionNode[]> = {};

View File

@@ -13,18 +13,6 @@
comment:
_nnull: true
- collection: directus_collections
action: read
- collection: directus_fields
action: read
- collection: directus_permissions
action: read
permissions:
role:
_eq: $CURRENT_ROLE
- collection: directus_presets
action: read
permissions:
@@ -60,9 +48,6 @@
user:
_eq: $CURRENT_USER
- collection: directus_relations
action: read
- collection: directus_roles
action: read
permissions:

View File

@@ -11,6 +11,10 @@ const defaults: Partial<Permission> = {
system: true,
};
const schemaPermissionsRaw = requireYAML(require.resolve('./schema-access-permissions.yaml')) as Permission[];
const permissions = requireYAML(require.resolve('./app-access-permissions.yaml')) as Permission[];
export const appAccessMinimalPermissions: Permission[] = permissions.map((row) => merge({}, defaults, row));
export const schemaPermissions: Permission[] = schemaPermissionsRaw.map((row) => merge({}, defaults, row));
export const appAccessMinimalPermissions: Permission[] = [...schemaPermissions, ...permissions].map((row) =>
merge({}, defaults, row)
);

View File

@@ -0,0 +1,17 @@
# NOTE: Activity/collections/fields/presets/relations/revisions will have an extra hardcoded filter
# to filter out collections you don't have read access
- collection: directus_collections
action: read
- collection: directus_fields
action: read
- collection: directus_permissions
action: read
permissions:
role:
_eq: $CURRENT_ROLE
- collection: directus_relations
action: read

View File

@@ -65,3 +65,6 @@ data:
note: $t:directus_collection.directus_panels
- collection: directus_notifications
note: $t:directus_collection.directus_notifications
- collection: directus_shares
icon: share
note: $t:directus_collection.directus_shares

View File

@@ -11,4 +11,4 @@ fields:
width: half
- field: user_agent
width: half
- field: data
- field: share

View File

@@ -0,0 +1,73 @@
table: directus_shares
fields:
- field: id
special: uuid
readonly: true
hidden: true
- field: name
- field: collection
width: half
hidden: true
- field: item
width: half
hidden: true
- field: role
interface: select-dropdown-m2o
width: half
options:
template: '{{name}}'
filter:
admin_access:
_eq: false
- field: password
special: hash,conceal
interface: input-hash
options:
iconRight: lock
masked: true
width: half
- field: date_start
width: half
- field: date_end
width: half
- field: max_uses
width: half
- field: times_used
width: half
readonly: true
- field: date_created
special: date-created
width: half
readonly: true
conditions:
- name: notCreatedYet
rule:
id:
_null: true
hidden: true
- field: user_created
special: user-created
interface: select-dropdown-m2o
width: half
display: user
options:
template: '{{avatar.$thumbnail}} {{first_name}} {{last_name}}'
readonly: true
conditions:
- name: notCreatedYet
rule:
id:
_null: true
hidden: true

View File

@@ -12,6 +12,9 @@ defaults:
sort_field: null
data:
- many_collection: directus_collections
many_field: group
one_collection: directus_collections
- many_collection: directus_users
many_field: role
one_collection: directus_roles
@@ -73,6 +76,9 @@ data:
- many_collection: directus_sessions
many_field: user
one_collection: directus_users
- many_collection: directus_sessions
many_field: share
one_collection: directus_shares
- many_collection: directus_settings
many_field: storage_default_folder
one_collection: directus_folders
@@ -88,3 +94,12 @@ data:
- many_collection: directus_notifications
many_field: sender
one_collection: directus_users
- many_collection: directus_shares
many_field: role
one_collection: directus_roles
- many_collection: directus_shares
many_field: collection
one_collection: directus_collections
- many_collection: directus_shares
many_field: user_created
one_collection: directus_users