Skip to content

Commit

Permalink
Merge pull request #982 from CSCfi/invitations
Browse files Browse the repository at this point in the history
Accepting invitation
  • Loading branch information
Macroz committed Mar 5, 2019
2 parents d235436 + 9dcc8b2 commit 121a23f
Show file tree
Hide file tree
Showing 15 changed files with 368 additions and 62 deletions.
19 changes: 19 additions & 0 deletions resources/sql/queries.sql
Original file line number Diff line number Diff line change
Expand Up @@ -637,3 +637,22 @@ VALUES (:apikey, :comment);
-- :name get-api-key :? :1
SELECT apiKey FROM api_key
WHERE apiKey = :apikey;

-- :name get-application-by-invitation-token :? :1
SELECT app.id
FROM catalogue_item_application app
JOIN application_event evt ON (app.id = evt.appid)
WHERE evt.eventdata->>'invitation/token' = :token

-- :name get-invitation-tokens :? :*
SELECT
evt.eventdata->>'event/type' AS event,
evt.eventdata->>'invitation/token' AS token,
evt.eventdata->>'event/actor' AS actor,
evt.eventdata->'application/member'->>'name' AS name,
evt.eventdata->'application/member'->>'email' AS email
FROM application_event evt
WHERE evt.eventdata->>'invitation/token' IS NOT NULL
/*~ (when (:appid params) */
AND appid = :appid
/*~ ) ~*/
10 changes: 6 additions & 4 deletions resources/translations/en.edn
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@
[:p "You agree not to introduce to REMS any information that relates to an identified or identifiable natural person."]
[:h3 "Acknowledgements"]
[:p "CSC’s work for REMS has been supported by the Ministry of Education and Culture of Finland and by Academy of Finland grants 271642 and 263164 to construct Biomedinfra, the Finnish consortium for ELIXIR, BBMRI and EATRIS ESFRI."]]]}
:actions {:add-member "Add member"
:actions {:accept-invitation "Accept invitation"
:accept-invitation-success [:div [:p "Joining the application was successful."] [:p "Next you will be taken to the application."]]
:accept-invitation-already-member [:div [:p "You are already a member."] [:p "Next you will be taken to the application."]]
:add-member "Add member"
:applicant "Applicant"
:application "Application"
:approve "Approve"
Expand All @@ -61,6 +64,7 @@
:decide "Decide"
:description "Description"
:empty "You don't have any applications to process."
:errors {:invalid-token [:div [:p "Joining the application failed."] [:p "Check the invitation token " [:code "%1"]]]}
:export-entitlements "Export entitlements as csv"
:handled-approvals "Handled applications"
:handled-reviews "Handled reviews"
Expand Down Expand Up @@ -154,6 +158,7 @@
:draft-saved "Modified"
:member-added "Member added"
:member-invited "Member invited"
:member-joined "Member joined"
:member-removed "Member removed"
:member-uninvited "Member uninvited"
:rejected "Rejected"
Expand Down Expand Up @@ -332,9 +337,6 @@
:administration "Administration"
:applications "Applications"
:catalogue "Catalogue"
:create-catalogue-item "Create catalogue item"
:create-license "Create license"
:create-resource "Create resource"
:home "Home"
:login "Login"
:logout "Sign Out"}
Expand Down
10 changes: 6 additions & 4 deletions resources/translations/fi.edn
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,10 @@
[:p "Sitoudut siihen, että et syötä REMS-demoon mitään tunnistettua tai tunnistettavissa olevaa luonnollista henkilöä koskevaa tietoa."]
[:h3 "Rahoittaja"]
[:p "CSC:n REMS-tuote on saanut rahoitusta Opetus- ja kulttuuriministeriöltä ja Suomen akatemialta (apurahat 271642 ja 263164 Biomedinfraa varten, joka on Suomen ELIXIR, BBMRI ja EATRIS-tutkimusinfrastruktuurisolmujen muodostama konsortio)."]]]}
:actions {:add-member "Add member"
:actions {:accept-invitation "Hyväksy kutsu"
:accept-invitation-success [:div [:p "Liittyminen hakemukseen onnistui."] [:p "Seuraavaksi pääset katsomaan hakemuksen tietoja."]]
:accept-invitation-already-member [:div. [:p "Olet jo jäsen."] [:p "Seuraavaksi pääset katsomaan hakemuksen tietoja."]]
:add-member "Lisää jäsen"
:applicant "Hakija"
:application "Hakemus"
:approve "Hyväksy"
Expand All @@ -61,6 +64,7 @@
:decide "Päätä"
:description "Kuvaus"
:empty "Sinulla ei ole hakemuksia käsiteltäväksi."
:errors {:invalid-token [:div [:p "Hakemukseen liittyminen epäonnistui."] [:p "Tarkista kutsukoodi " [:code "%1"]]]}
:export-entitlements "Lataa käyttöoikeudet csv-tiedostona"
:handled-approvals "Käsitellyt hakemukset"
:handled-reviews "Käsitellyt katselmoinnit"
Expand Down Expand Up @@ -154,6 +158,7 @@
:draft-saved "Muokattu"
:member-added "Lisätty jäsen"
:member-invited "Kutsuttu jäsen"
:member-joined "Jäsen liittyi"
:member-removed "Poistettu jäsen"
:member-uninvited "Poistettu jäsen"
:rejected "Hylätty"
Expand Down Expand Up @@ -333,9 +338,6 @@
:administration "Ylläpito"
:applications "Hakemukset"
:catalogue "Aineistoluettelo"
:create-catalogue-item "Luo uusi aineisto luetteloon"
:create-license "Luo lisenssi"
:create-resource "Luo resurssi"
:home "Etusivu"
:login "Kirjaudu sisään"
:logout "Kirjaudu ulos"}
Expand Down
20 changes: 17 additions & 3 deletions src/clj/rems/api/applications.clj
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,11 @@
:application-id s/Num
s/Keyword s/Any})

(s/defschema AcceptInvitationResult
{:success s/Bool
(s/optional-key :application-id) s/Num
(s/optional-key :errors) [s/Any]})

;; Api implementation

(defn- api-judge [{:keys [command application-id round comment actor]}]
Expand Down Expand Up @@ -143,12 +148,13 @@
(let [is-handler? (or (contains? (set (applications/get-handlers (:application application))) user) ; old form
(contains? (get-in application [:application :possible-commands]) :see-everything))] ; dynamic
(if is-handler?
application
(update-in application [:application] dissoc :invitation-tokens)
(-> application
(update-in [:application :events] hide-sensitive-events)
(update-in [:application :dynamic-events] dynamic/hide-sensitive-dynamic-events)
(update-in [:application :events] hide-users)
(update-in [:application :workflow] dissoc :handlers)))))
(update-in [:application :workflow] dissoc :handlers)
(update-in [:application] dissoc :invitation-tokens)))))

(defn api-get-application [user-id application-id]
(when (not (empty? (db/get-applications {:id application-id})))
Expand Down Expand Up @@ -199,7 +205,8 @@
(defn- get-user-applications [user-id]
;; XXX: the old API doesn't know about members, so rems.db.applications/get-user-applications doesn't return applications where the user is a member
;; XXX: this code cannot be moved to rems.db.applications/get-user-applications because it would create cyclic dependencies
(let [old-applications (applications/get-user-applications user-id)
(let [old-applications (->> (applications/get-user-applications user-id)
(map #(:application (hide-sensitive-information {:application %} user-id))))
member-application-ids (->> (applications/get-dynamic-application-events-since 0)
(reduce dynamic-roles/permissions-of-all-applications nil)
(filter (fn [[_id app]]
Expand Down Expand Up @@ -263,6 +270,13 @@
(content-type (:type attachment))))
(not-found! "not found"))))

(POST "/accept-invitation" []
:summary "Accept an invitation by token"
:roles #{:logged-in}
:query-params [invitation-token :- (describe s/Str "invitation token")]
:return AcceptInvitationResult
(ok (applications/accept-invitation (getx-user-id) invitation-token)))

(GET "/:application-id" []
:summary "Get application by `application-id`"
:roles #{:logged-in}
Expand Down
6 changes: 5 additions & 1 deletion src/clj/rems/api/applications_v2.clj
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@
[application event]
application)

(defmethod event-type-specific-application-view :application.event/member-joined
[application event]
application)

(defmethod event-type-specific-application-view :application.event/member-removed
[application event]
application)
Expand Down Expand Up @@ -513,7 +517,7 @@
(update :application/workflow dissoc :workflow.dynamic/handlers)))

(defn- apply-user-permissions [application user-id]
(let [see-application? (permissions/has-any-role? application user-id)
(let [see-application? (dynamic/see-application? application user-id)
permissions (permissions/user-permissions application user-id)
see-everything? (contains? permissions :see-everything)]
(when see-application?
Expand Down
34 changes: 27 additions & 7 deletions src/clj/rems/db/applications.clj
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
[rems.form-validation :as form-validation]
[rems.json :as json]
[rems.permissions :as permissions]
[rems.util :refer [get-username]]
[rems.util :refer [get-username secure-token]]
[rems.workflow.dynamic :as dynamic]
[schema-tools.core :as st]
[schema.coerce :as coerce]
Expand Down Expand Up @@ -243,7 +243,7 @@
(is-approver? user-id application-id)
(is-reviewer? user-id application-id)
(is-third-party-reviewer? user-id application)
(permissions/has-any-role? application user-id))))
(dynamic/see-application? application user-id))))

(defn can-close? [user-id application]
(assert user-id)
Expand Down Expand Up @@ -327,7 +327,8 @@

(defn get-approvals [user-id]
(->> (get-applications-impl-batch user-id {})
(filterv (partial can-approve? user-id))))
(filterv (partial can-approve? user-id))
(map #(dissoc % :invitation-tokens)))) ; TODO use same hiding in all applications lists

(comment
(->> (get-approvals "developer")
Expand All @@ -345,7 +346,8 @@
(let [application (get-application-state (:id app))]
(if (is-dynamic-application? application)
(contains? (set (actors-of-dynamic-application application)) user-id)
(is-actor? user-id (actors/filter-by-application-id actors (:id app))))))))))
(is-actor? user-id (actors/filter-by-application-id actors (:id app)))))))
(map #(dissoc % :invitation-tokens))))) ; TODO use same hiding in all applications lists

(comment
(->> (get-handled-approvals "developer")
Expand All @@ -360,7 +362,8 @@
(or (is-actor? user-id (actors/filter-by-application-id actors (:id app)))
(is-third-party-reviewer? user-id app)
(is-commenter? user-id app)
(is-decider? user-id app)))))))
(is-decider? user-id app))))
(map #(dissoc % :invitation-tokens))))) ; TODO use same hiding in all applications lists

(comment
(get-handled-reviews "bob")
Expand Down Expand Up @@ -396,7 +399,8 @@
(can-third-party-review? user-id app)
(can-comment? user-id (:id app))
(can-decide? user-id (:id app))))))
(mapv (partial assoc-review-type-to-app user-id))))
(mapv (partial assoc-review-type-to-app user-id))
(map #(dissoc % :invitation-tokens)))) ; TODO use same hiding in all applications lists

(defn make-draft-application
"Make a draft application with an initial set of catalogue items."
Expand Down Expand Up @@ -1065,7 +1069,8 @@

(def ^:private db-injections
{:valid-user? valid-user?
:validate-form validate-form})
:validate-form validate-form
:secure-token secure-token})

(defn dynamic-command! [cmd]
(assert (:application-id cmd))
Expand All @@ -1081,3 +1086,18 @@
;; TODO use also in UI side?
(defn is-dynamic-application? [application]
(= :workflow/dynamic (get-in application [:workflow :type])))

(defn accept-invitation [user-id invitation-token]
(or (when-let [application-id (:id (db/get-application-by-invitation-token {:token invitation-token}))]
(let [response (dynamic-command! {:type :rems.workflow.dynamic/accept-invitation
:actor user-id
:application-id application-id
:token invitation-token
:time (time/now)})]
(if-not response
{:success true
:application-id application-id}
{:success false
:errors (:errors response)})))
{:success false
:errors [{:type :t.actions.errors/invalid-token :token invitation-token}]}))
2 changes: 1 addition & 1 deletion src/clj/rems/db/dynamic_roles.clj
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
{:event/type :application.event/created
:event/actor "applicant-and-handler"
:application/id 2}]]
(is (= #{:applicant}
(is (= #{:applicant :everyone-else}
(roles-from-all-applications "applicant-only" events)))
(is (= #{:applicant :handler}
(roles-from-all-applications "applicant-and-handler" events)))))
Expand Down
1 change: 1 addition & 0 deletions src/clj/rems/home.clj
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@

(defroutes home-routes
(GET "/" [] (layout/home-page))
(GET "/accept-invitation" {{:keys [token]} :params} (redirect (str "/#/application/accept-invitation/" token)))
(GET "/apply-for" {{:keys [resource]} :params} (apply-for-resource resource))
(GET "/landing_page" req (redirect "/#/redirect")) ; DEPRECATED: legacy url redirect
(GET "/markdown/:filename" [filename] (markdown-page filename))
Expand Down
19 changes: 5 additions & 14 deletions src/clj/rems/permissions.clj
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@
(update ::user-roles dissoc-if-empty user)))

(defn user-roles [application user]
(set (get-in application [::user-roles user])))
(let [specific-roles (set (get-in application [::user-roles user]))]
(if (seq specific-roles)
specific-roles
#{:everyone-else})))

(deftest test-user-roles
(testing "give first role"
Expand Down Expand Up @@ -61,19 +64,7 @@
(give-role-to-user :role-2 "user-2"))]
(is (= #{:role-1} (user-roles app "user-1")))
(is (= #{:role-2} (user-roles app "user-2")))
(is (= #{} (user-roles app "user-3"))))))

(defn has-any-role? [application user]
(seq (user-roles application user)))

(deftest test-has-any-role?
(testing "no roles"
(is (not (-> {}
(has-any-role? "user")))))
(testing "some roles"
(is (-> {}
(give-role-to-user :role "user")
(has-any-role? "user")))))
(is (= #{:everyone-else} (user-roles app "user-3"))))))

(defn set-role-permissions
"Sets role specific permissions for the application.
Expand Down
7 changes: 7 additions & 0 deletions src/clj/rems/util.clj
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
(ns rems.util
(:require [clojure.test :refer [deftest is]]
[buddy.core.nonce :as buddy-nonce]
[buddy.core.codecs :as buddy-codecs]
[rems.config :refer [env]]
[rems.context :as context]))

Expand Down Expand Up @@ -71,3 +73,8 @@
(is (= {:a 1} (update-present {:a 1} :b (constantly true))))
(is (= {:a 1 :b true} (update-present {:a 1 :b 2} :b (constantly true))))
(is (= {:a 1 :b true} (update-present {:a 1 :b nil} :b (constantly true)))))

(defn secure-token
[]
(let [randomdata (buddy-nonce/random-bytes 16)]
(buddy-codecs/bytes->hex randomdata)))
Loading

0 comments on commit 121a23f

Please sign in to comment.