diff --git a/backend/src/app/migrations.clj b/backend/src/app/migrations.clj index e43cc92f82..5c89f83e2b 100644 --- a/backend/src/app/migrations.clj +++ b/backend/src/app/migrations.clj @@ -424,7 +424,10 @@ :fn (mg/resource "app/migrations/sql/0133-mod-file-table.sql")} {:name "0134-mod-file-change-table" - :fn (mg/resource "app/migrations/sql/0134-mod-file-change-table.sql")}]) + :fn (mg/resource "app/migrations/sql/0134-mod-file-change-table.sql")} + + {:name "0135-mod-team-invitation-table.sql" + :fn (mg/resource "app/migrations/sql/0135-mod-team-invitation-table.sql")}]) (defn apply-migrations! [pool name migrations] diff --git a/backend/src/app/migrations/sql/0135-mod-team-invitation-table.sql b/backend/src/app/migrations/sql/0135-mod-team-invitation-table.sql new file mode 100644 index 0000000000..8662f89d49 --- /dev/null +++ b/backend/src/app/migrations/sql/0135-mod-team-invitation-table.sql @@ -0,0 +1,2 @@ +ALTER TABLE team_invitation + ADD COLUMN created_by uuid NULL REFERENCES profile(id) ON DELETE SET NULL; diff --git a/backend/src/app/rpc/commands/auth.clj b/backend/src/app/rpc/commands/auth.clj index 1ed3fa364d..062436dbe6 100644 --- a/backend/src/app/rpc/commands/auth.clj +++ b/backend/src/app/rpc/commands/auth.clj @@ -383,7 +383,9 @@ invitation (when-let [token (:invitation-token params)] (tokens/verify (::setup/props cfg) {:token token :iss :team-invitation})) - props (audit/profile->props profile) + props (-> (audit/profile->props profile) + (assoc :from-invitation (some? invitation))) + create-welcome-file-when-needed (fn [] diff --git a/backend/src/app/rpc/commands/teams.clj b/backend/src/app/rpc/commands/teams.clj index 35fe16ea6e..5bb92c5df4 100644 --- a/backend/src/app/rpc/commands/teams.clj +++ b/backend/src/app/rpc/commands/teams.clj @@ -759,8 +759,8 @@ ;; --- Mutation: Create Team Invitation (def sql:upsert-team-invitation - "insert into team_invitation(id, team_id, email_to, role, valid_until) - values (?, ?, ?, ?, ?) + "insert into team_invitation(id, team_id, email_to, role, valid_until, created_by) + values (?, ?, ?, ?, ?, ?) on conflict(team_id, email_to) do update set role = ?, valid_until = ?, updated_at = now() returning *") @@ -853,6 +853,7 @@ invitation (db/exec-one! conn [sql:upsert-team-invitation id (:id team) (str/lower email) (name role) expire + (:id profile) (name role) expire]) updated? (not= id (:id invitation)) profile-id (:id profile) diff --git a/backend/src/app/rpc/commands/verify_token.clj b/backend/src/app/rpc/commands/verify_token.clj index 7f0dd6b5fb..5dcd2a3e5c 100644 --- a/backend/src/app/rpc/commands/verify_token.clj +++ b/backend/src/app/rpc/commands/verify_token.clj @@ -167,12 +167,24 @@ (let [props {:team-id (:team-id claims) :role (:role claims) :invitation-id (:id invitation)} - event (-> (audit/event-from-rpc-params params) - (assoc ::audit/name "accept-team-invitation") - (assoc ::audit/props props))] + + accept-invitation-event + (-> (audit/event-from-rpc-params params) + (assoc ::audit/name "accept-team-invitation") + (assoc ::audit/props props)) + + accept-invitation-from-event + (-> (audit/event-from-rpc-params params) + (assoc ::audit/profile-id (:created-by invitation)) + (assoc ::audit/name "accept-team-invitation-from") + (assoc ::audit/props (assoc props + :profile-id (:id profile) + :email (:email profile))))] + + (audit/submit! cfg accept-invitation-event) + (audit/submit! cfg accept-invitation-from-event) (accept-invitation cfg claims invitation profile) - (audit/submit! cfg event) (assoc claims :state :created)) (ex/raise :type :validation diff --git a/frontend/src/app/main/ui/dashboard/grid.cljs b/frontend/src/app/main/ui/dashboard/grid.cljs index 8883149d05..d83ae0c66d 100644 --- a/frontend/src/app/main/ui/dashboard/grid.cljs +++ b/frontend/src/app/main/ui/dashboard/grid.cljs @@ -457,12 +457,14 @@ on-drop (mf/use-fn (fn [e] - (when (and (not (dnd/has-type? e "penpot/files")) - (or (dnd/has-type? e "Files") - (dnd/has-type? e "application/x-moz-file"))) - (dom/prevent-default e) - (reset! dragging? false) - (import-files (.-files (.-dataTransfer e))))))] + (if can-edit + (when (and (not (dnd/has-type? e "penpot/files")) + (or (dnd/has-type? e "Files") + (dnd/has-type? e "application/x-moz-file"))) + (dom/prevent-default e) + (reset! dragging? false) + (import-files (.-files (.-dataTransfer e)))) + (dom/prevent-default e))))] [:div {:class (stl/css :dashboard-grid) :dragabble (dm/str can-edit) @@ -576,24 +578,26 @@ on-drop (mf/use-fn - (mf/deps files selected-files) + (mf/deps files selected-files can-edit) (fn [e] - (cond - (dnd/has-type? e "penpot/files") - (do - (reset! dragging? false) - (when (not= selected-project project-id) - (let [data {:ids (into #{} (keys selected-files)) - :project-id project-id} - mdata {:on-success on-drop-success}] - (st/emit! (dd/move-files (with-meta data mdata)))))) + (if can-edit + (cond + (dnd/has-type? e "penpot/files") + (do + (reset! dragging? false) + (when (not= selected-project project-id) + (let [data {:ids (into #{} (keys selected-files)) + :project-id project-id} + mdata {:on-success on-drop-success}] + (st/emit! (dd/move-files (with-meta data mdata)))))) - (or (dnd/has-type? e "Files") - (dnd/has-type? e "application/x-moz-file")) - (do - (dom/prevent-default e) - (reset! dragging? false) - (import-files (.-files (.-dataTransfer e)))))))] + (or (dnd/has-type? e "Files") + (dnd/has-type? e "application/x-moz-file")) + (do + (dom/prevent-default e) + (reset! dragging? false) + (import-files (.-files (.-dataTransfer e))))) + (dom/prevent-default e))))] [:div {:class (stl/css :dashboard-grid) :dragabble (dm/str can-edit) diff --git a/frontend/src/app/main/ui/workspace/main_menu.cljs b/frontend/src/app/main/ui/workspace/main_menu.cljs index d870e3ac51..7d9413bd08 100644 --- a/frontend/src/app/main/ui/workspace/main_menu.cljs +++ b/frontend/src/app/main/ui/workspace/main_menu.cljs @@ -686,10 +686,12 @@ (dp/open-plugin! manifest user-can-edit?)))))] [:> dropdown-menu-item* {:key (dm/str "plugins-menu-" idx) :on-click on-click - :title (when-not can-open? (tr "workspace.plugins.error.need-editor")) :class (stl/css-case :submenu-item true :menu-disabled (not can-open?)) :on-key-down on-key-down} - [:span {:class (stl/css :item-name)} name]]))]))) + [:span {:class (stl/css :item-name)} name] + (when-not can-open? + [:span {:class (stl/css :item-icon) + :title (tr "workspace.plugins.error.need-editor")} i/help])]))]))) (mf/defc menu {::mf/props :obj} diff --git a/frontend/src/app/main/ui/workspace/main_menu.scss b/frontend/src/app/main/ui/workspace/main_menu.scss index 56ae1cd190..5ffd8efaa1 100644 --- a/frontend/src/app/main/ui/workspace/main_menu.scss +++ b/frontend/src/app/main/ui/workspace/main_menu.scss @@ -113,3 +113,10 @@ top: $s-192; } } + +.item-icon { + svg { + @extend .button-icon; + stroke: var(--icon-foreground); + } +}