group adding/adding

This commit is contained in:
Roman Volosovskyi 2016-11-25 09:19:06 +02:00
parent ce63e17a31
commit d1c8912cf5
11 changed files with 230 additions and 103 deletions

View File

@ -406,9 +406,8 @@
(register-handler :add-chat (register-handler :add-chat
(u/side-effect! (u/side-effect!
(fn [{:keys [chats]} [_ chat-id chat]] (fn [_ [_ chat-id chat]]
(when-not (get chats chat-id) (dispatch [::add-chat chat-id chat]))))
(dispatch [::add-chat chat-id chat])))))
(register-handler ::add-chat (register-handler ::add-chat
(-> add-new-chat (-> add-new-chat
@ -572,3 +571,29 @@
(let [chat (-> (chats/get-by-id chat-id) (let [chat (-> (chats/get-by-id chat-id)
(update :clock-value inc))] (update :clock-value inc))]
(dispatch [:update-chat! chat]))))) (dispatch [:update-chat! chat])))))
(register-handler :update-group-message
(u/side-effect!
(fn [{:keys [current-public-key web3 chats]}
[_ {:keys [from]
{:keys [group-id keypair timestamp]} :payload}]]
(let [{:keys [private public]} keypair]
(let [{:keys [updated-at removed-at]} (chats/get-by-id group-id)
is-active (chats/is-active? group-id)
chat {:chat-id group-id
:public-key public
:private-key private
:updated-at timestamp}]
(when (and (= from (get-in chats [group-id :group-admin]))
(or (not (chats/exists? group-id))
is-active
(> timestamp removed-at)
(> timestamp updated-at)))
(dispatch [:update-chat! chat])
(when is-active
(protocol/start-watching-group!
{:web3 web3
:group-id group-id
:identity current-public-key
:keypair keypair
:callback #(dispatch [:incoming-message %1 %2])}))))))))

View File

@ -58,13 +58,13 @@
(dispatch [:upsert-chat! {:chat-id chat-id' (dispatch [:upsert-chat! {:chat-id chat-id'
:group-chat group-chat? :group-chat group-chat?
:clock-value clock-value}]) :clock-value clock-value}])
(dispatch [::add-message chat-id message']) (dispatch [::add-message chat-id' message'])
(when (= (:content-type message') content-type-command-request) (when (= (:content-type message') content-type-command-request)
(dispatch [:add-request chat-id' message'])) (dispatch [:add-request chat-id' message']))
(dispatch [:add-unviewed-message chat-id' message-id])) (dispatch [:add-unviewed-message chat-id' message-id]))
(if (and (if (and
(= (:content-type message) content-type-command) (= (:content-type message) content-type-command)
(not= chat-id wallet-chat-id) (not= chat-id' wallet-chat-id)
(= "send" (get-in message [:content :command]))) (= "send" (get-in message [:content :command])))
(add-message-to-wallet db message))))) (add-message-to-wallet db message)))))

View File

@ -39,9 +39,10 @@
(defview message-input [input-options set-layout-size] (defview message-input [input-options set-layout-size]
[input-message [:get-chat-input-text] [input-message [:get-chat-input-text]
disable? [:get :disable-input]] disable? [:get :disable-input]
active? [:chat :is-active]]
[text-input (merge [text-input (merge
(plain-input-options disable?) (plain-input-options (or disable? (not active?)))
{:placeholder-text-color :#c0c5c9 {:placeholder-text-color :#c0c5c9
:auto-focus false :auto-focus false
:blur-on-submit true :blur-on-submit true

View File

@ -10,6 +10,8 @@
:default default-chat-color} :default default-chat-color}
:group-chat {:type :bool :group-chat {:type :bool
:indexed true} :indexed true}
:group-admin {:type :string
:optional true}
:is-active :bool :is-active :bool
:timestamp :int :timestamp :int
:contacts {:type :list :contacts {:type :list
@ -20,6 +22,12 @@
:optional true} :optional true}
:removed-at {:type :int :removed-at {:type :int
:optional true} :optional true}
:removed-from-at {:type :int
:optional true}
:added-to-at {:type :int
:optional true}
:updated-at {:type :int
:optional true}
:last-message-id :string :last-message-id :string
:public-key {:type :string :public-key {:type :string
:optional true} :optional true}

View File

@ -80,10 +80,45 @@
(chats/remove-contacts current-chat-id selected-participants)) (chats/remove-contacts current-chat-id selected-participants))
(defn notify-about-removing! (defn notify-about-removing!
[{:keys [current-chat-id selected-participants]} _] [{:keys [web3 current-chat-id selected-participants chats current-public-key]} _]
(doseq [participant selected-participants] (let [{:keys [private public] :as new-keypair} (protocol/new-keypair!)
;;todo implement {:keys [name private-key public-key]
)) :as chat} (get chats current-chat-id)
old-keypair {:private private-key
:public public-key}
contacts (get chat :contacts)
identities (-> (map :identity contacts)
set
(clojure.set/difference selected-participants))]
(dispatch [:update-chat! {:chat-id current-chat-id
:private-key private
:public-key public}])
(doseq [participant selected-participants]
(let [id (random/id)]
(doseq [keypair [old-keypair new-keypair]]
(protocol/remove-from-group!
{:web3 web3
:group-id current-chat-id
:identity participant
:keypair keypair
:message {:from current-public-key
:message-id id}}))))
(protocol/start-watching-group!
{:web3 web3
:group-id current-chat-id
:identity current-public-key
:keypair new-keypair
:callback #(dispatch [:incoming-message %1 %2])})
(protocol/update-group!
{:web3 web3
:group {:id current-chat-id
:name name
:contacts (conj identities current-public-key)
:admin current-public-key
:keypair new-keypair}
:identities identities
:message {:from current-public-key
:message-id (random/id)}})))
(defn system-message [message-id content] (defn system-message [message-id content]
{:from "system" {:from "system"
@ -113,7 +148,7 @@
;; about the api call that removes participants from the group? ;; about the api call that removes participants from the group?
((after remove-members-from-chat!)) ((after remove-members-from-chat!))
;; todo uncomment ;; todo uncomment
;((after notify-about-removing!)) ((after notify-about-removing!))
((after create-removing-messages!)) ((after create-removing-messages!))
((enrich deselect-members)) ((enrich deselect-members))
debug)) debug))
@ -130,25 +165,40 @@
(defn notify-about-new-members! (defn notify-about-new-members!
[{:keys [current-chat-id selected-participants [{:keys [current-chat-id selected-participants
current-public-key chats web3]} _] current-public-key chats web3]} _]
(let [{:keys [public-key private-key name contacts]} (chats current-chat-id) (let [{:keys [name contacts]} (chats current-chat-id)
identities (map :identity contacts) identities (map :identity contacts)
keypair {:public public-key
:private private-key}] {:keys [public private]
:as new-keypair} (protocol/new-keypair!)
group-message {:web3 web3
:group {:id current-chat-id
:name name
:contacts (conj identities current-public-key)
:admin current-public-key}
:message {:from current-public-key
:message-id (random/id)}}]
(dispatch [:update-chat! {:chat-id current-chat-id
:public-key public
:private-key private}])
(protocol/start-watching-group! {:web3 web3
:group-id current-chat-id
:identity current-public-key
:keypair new-keypair
:callback #(dispatch [:incoming-message %1 %2])})
(protocol/invite-to-group! (protocol/invite-to-group!
{:web3 web3 (-> group-message
:group {:id current-chat-id (assoc-in [:group :keypair] new-keypair)
:name name (assoc :identities selected-participants)))
:contacts (conj identities current-public-key) (protocol/update-group!
:admin current-public-key (-> group-message
:keypair keypair} (assoc-in [:group :keypair] new-keypair)
:identities selected-participants (assoc :identities identities)))
:message {:from current-public-key
:message-id (random/id)}})
(doseq [identity selected-participants] (doseq [identity selected-participants]
(protocol/add-to-group! {:web3 web3 (protocol/add-to-group! {:web3 web3
:group-id current-chat-id :group-id current-chat-id
:identity identity :identity identity
:keypair keypair :keypair new-keypair
:message {:from current-public-key :message {:from current-public-key
:message-id (random/id)}})))) :message-id (random/id)}}))))

View File

@ -37,8 +37,9 @@
[view st/modal-inner-container [view st/modal-inner-container
[text {:style st/modal-member-name} name] [text {:style st/modal-member-name} name]
[touchable-highlight {:on-press remove-member} [touchable-highlight {:on-press remove-member}
[text {:style st/modal-remove-text} [view
(label :t/remove)]]]]])) [text {:style st/modal-remove-text}
(label :t/remove)]]]]]]))
(defview chat-members [] (defview chat-members []
[members [:current-chat-contacts]] [members [:current-chat-contacts]]
@ -145,19 +146,26 @@
(when (pos? (count validation-messages)) (when (pos? (count validation-messages))
[text {:style st/chat-name-validation-message} (first validation-messages)])]) [text {:style st/chat-name-validation-message} (first validation-messages)])])
(defview members []
[current-pk [:get :current-public-key]
group-admin [:chat :group-admin]]
(when (= current-pk group-admin)
[view
[text {:style st/members-text} (label :t/members-title)]
[touchable-highlight {:on-press #(dispatch [:navigate-to :add-participants])}
;; TODO add participants view is not in design
[view st/add-members-container
[icon :add_gray st/add-members-icon]
[text {:style st/add-members-text}
(label :t/add-members)]]]
[chat-members]]))
(defn group-settings [] (defn group-settings []
[view st/group-settings [view st/group-settings
[new-group-toolbar] [new-group-toolbar]
[scroll-view st/body [scroll-view st/body
[chat-name] [chat-name]
[text {:style st/members-text} (label :t/members-title)] [members]
[touchable-highlight {:on-press #(dispatch [:navigate-to :add-participants])}
;; TODO add participants view is not in design
[view st/add-members-container
[icon :add_gray st/add-members-icon]
[text {:style st/add-members-text}
(label :t/add-members)]]]
[chat-members]
[text {:style st/settings-text} [text {:style st/settings-text}
(label :t/settings)] (label :t/settings)]
[settings-view]] [settings-view]]

View File

@ -30,8 +30,8 @@
(s/join ", "))) (s/join ", ")))
(defn prepare-chat (defn prepare-chat
[{:keys [selected-contacts] :as db} [_ group-name]] [{:keys [selected-contacts current-public-key] :as db} [_ group-name]]
(let [contacts (mapv #(hash-map :identity %) selected-contacts) (let [contacts (mapv #(hash-map :identity %) selected-contacts)
chat-name (if-not (s/blank? group-name) chat-name (if-not (s/blank? group-name)
group-name group-name
(group-name-from-contacts db)) (group-name-from-contacts db))
@ -42,6 +42,7 @@
:name chat-name :name chat-name
:color default-chat-color :color default-chat-color
:group-chat true :group-chat true
:group-admin current-public-key
:is-active true :is-active true
:timestamp (.getTime (js/Date.)) :timestamp (.getTime (js/Date.))
:contacts contacts}))) :contacts contacts})))
@ -92,28 +93,31 @@
(register-handler :group-chat-invite-received (register-handler :group-chat-invite-received
(u/side-effect! (u/side-effect!
(fn [{:keys [current-public-key web3] :as db} (fn [{:keys [current-public-key web3]}
[_ {{:keys [group-id group-name contacts keypair timestamp] :as payload} :payload}]] [_ {:keys [from]
{:keys [group-id group-name contacts keypair timestamp]} :payload}]]
(let [{:keys [private public]} keypair] (let [{:keys [private public]} keypair]
(let [removed-at (chats/removed-at group-id) (let [removed-at (chats/removed-at group-id)
is-active (chats/is-active? group-id) contacts' (keep (fn [ident]
contacts' (keep (fn [ident] (when (not= ident current-public-key)
(when (not= ident current-public-key) {:identity ident})) contacts)
{:identity ident})) contacts) chat {:name group-name
chat {:name group-name :group-chat true
:group-chat true :group-admin from
:public-key public :public-key public
:private-key private :private-key private
:contacts contacts'}] :contacts contacts'
(when (or (not (chats/exists? group-id)) :added-to-at timestamp
is-active :timestamp timestamp
(> timestamp removed-at)) :is-active true}
(dispatch [:add-chat group-id (assoc chat :is-active true {:keys [removed-from-at] :as chat-from-db} (chats/get-by-id group-id)]
:timestamp timestamp)]) (when (or (not chat-from-db)
(when-not is-active (and (> timestamp removed-at)
(protocol/start-watching-group! (> timestamp removed-from-at)))
{:web3 web3 (dispatch [:add-chat group-id chat])
:group-id group-id (protocol/start-watching-group!
:identity current-public-key {:web3 web3
:keypair keypair :group-id group-id
:callback #(dispatch [:incoming-message %1 %2])})))))))) :identity current-public-key
:keypair keypair
:callback #(dispatch [:incoming-message %1 %2])})))))))

View File

@ -63,21 +63,15 @@
(defn init-whisper! (defn init-whisper!
[{:keys [rpc-url identity groups callback [{:keys [rpc-url identity groups callback
hashtags contacts profile-keypair pending-messages] contacts profile-keypair pending-messages]
:as options}] :as options}]
{:pre [(valid? ::options options)]} {:pre [(valid? ::options options)]}
(debug :init-whisper) (debug :init-whisper)
(stop-watching-all!) (stop-watching-all!)
(d/reset-all-pending-messages!) (d/reset-all-pending-messages!)
(let [web3 (u/make-web3 rpc-url) (let [web3 (u/make-web3 rpc-url)
listener-options {:web3 web3 listener-options {:web3 web3
:identity identity}] :identity identity}]
;; start listening to user's inbox
(f/add-filter!
web3
{:to identity
:topics [f/status-topic]}
(l/message-listener (assoc listener-options :callback callback)))
;; start listening to groups ;; start listening to groups
(doseq [{:keys [chat-id keypair]} groups] (doseq [{:keys [chat-id keypair]} groups]
(f/add-filter! (f/add-filter!
@ -85,6 +79,12 @@
{:topics [chat-id]} {:topics [chat-id]}
(l/message-listener (assoc listener-options :callback callback (l/message-listener (assoc listener-options :callback callback
:keypair keypair)))) :keypair keypair))))
;; start listening to user's inbox
(f/add-filter!
web3
{:to identity
:topics [f/status-topic]}
(l/message-listener (assoc listener-options :callback callback)))
;; start listening to profiles ;; start listening to profiles
(doseq [{:keys [identity keypair]} contacts] (doseq [{:keys [identity keypair]} contacts]
(watch-user! {:web3 web3 (watch-user! {:web3 web3

View File

@ -66,9 +66,11 @@
(s/def :group/name string?) (s/def :group/name string?)
(s/def :group/id string?) (s/def :group/id string?)
(s/def :group/admin string?)
(s/def :group/contacts (s/* string?)) (s/def :group/contacts (s/* string?))
(s/def ::group (s/def ::group
(s/keys :req-un [:group/name :group/id :group/contacts :message/keypair])) (s/keys :req-un
[:group/name :group/id :group/contacts :message/keypair :group/admin]))
(s/def :invite/options (s/def :invite/options
(s/keys :req-un [:options/web3 :protocol/message ::group ::identities])) (s/keys :req-un [:options/web3 :protocol/message ::group ::identities]))

View File

@ -83,7 +83,9 @@
(dispatch [:pending-message-remove message])) (dispatch [:pending-message-remove message]))
:seen (dispatch [:message-seen message]) :seen (dispatch [:message-seen message])
:group-invitation (dispatch [:group-chat-invite-received message]) :group-invitation (dispatch [:group-chat-invite-received message])
:update-group (dispatch [:update-group-message message])
:add-group-identity (dispatch [:participant-invited-to-group message]) :add-group-identity (dispatch [:participant-invited-to-group message])
:remove-group-identity (dispatch [:participant-removed-from-group message])
:leave-group (dispatch [:participant-left-group message]) :leave-group (dispatch [:participant-left-group message])
:contact-request (dispatch [:contact-request-received message]) :contact-request (dispatch [:contact-request-received message])
:discover (dispatch [:status-received message]) :discover (dispatch [:status-received message])
@ -117,23 +119,22 @@
invitee-name (if (= identity current-identity) invitee-name (if (= identity current-identity)
(label :t/You) (label :t/You)
(:name (contacts/get-by-id identity)))] (:name (contacts/get-by-id identity)))]
(messages/save chat-id {:from "system" {:from "system"
:message-id message-id :group-id chat-id
:content (str (or inviter-name from) " " (label :t/invited) " " (or invitee-name identity)) :message-id message-id
:content-type text-content-type}))) :content (str (or inviter-name from) " " (label :t/invited) " " (or invitee-name identity))
:content-type text-content-type}))
(defn participant-removed-from-group-message [chat-id identity from message-id] (defn participant-removed-from-group-message [identity from message-id]
(let [remover-name (:name (contacts/get-by-id from)) (let [remover-name (:name (contacts/get-by-id from))
removed-name (:name (contacts/get-by-id identity))] removed-name (:name (contacts/get-by-id identity))]
(->> (str (or remover-name from) " " (label :t/removed) " " (or removed-name identity)) (->> (str (or remover-name from) " " (label :t/removed) " " (or removed-name identity))
(system-message message-id) (system-message message-id))))
(messages/save chat-id))))
(defn you-removed-from-group-message [chat-id from message-id] (defn you-removed-from-group-message [from message-id]
(let [remover-name (:name (contacts/get-by-id from))] (let [remover-name (:name (contacts/get-by-id from))]
(->> (str (or remover-name from) " " (label :t/removed-from-chat)) (->> (str (or remover-name from) " " (label :t/removed-from-chat))
(system-message message-id) (system-message message-id))))
(messages/save chat-id))))
(defn participant-left-group-message [chat-id from message-id] (defn participant-left-group-message [chat-id from message-id]
(let [left-name (:name (contacts/get-by-id from))] (let [left-name (:name (contacts/get-by-id from))]
@ -149,17 +150,38 @@
(register-handler :participant-removed-from-group (register-handler :participant-removed-from-group
(u/side-effect! (u/side-effect!
(fn [_ [action from group-id identity message-id]] (fn [{:keys [current-public-key chats]}
(log/debug action message-id from group-id identity) [_ {:keys [from]
(chats/remove-contacts group-id [identity]) {:keys [group-id identity message-id]} :payload
(participant-removed-from-group-message group-id identity from message-id)))) :as message}]]
(when-not (messages/get-by-id message-id)
(let [admin (get-in chats [group-id :group-admin])]
(when (= admin from)
(if (= current-public-key identity)
(dispatch [::you-removed-from-group message])
(let [message
(assoc
(participant-removed-from-group-message identity from message-id)
:group-id group-id)]
(chats/remove-contacts group-id [identity])
(dispatch [:received-message message])))))))))
(register-handler :you-removed-from-group (register-handler ::you-removed-from-group
(u/side-effect! (u/side-effect!
(fn [_ [action from group-id message-id]] (fn [{:keys [web3]}
(log/debug action message-id from group-id) [_ {:keys [from]
(you-removed-from-group-message group-id from message-id) {:keys [group-id message-id timestamp]} :payload}]]
(chats/set-active group-id false)))) (let [{:keys [added-to-at]} (chats/get-by-id group-id)]
(when (> timestamp added-to-at)
(let [message
(-> (you-removed-from-group-message from message-id)
(assoc :group-id group-id))]
(dispatch [:received-message message]))
(protocol/stop-watching-group! {:web3 web3
:group-id group-id})
(dispatch [:update-chat! {:chat-id group-id
:removed-from-at timestamp
:is-active false}]))))))
(register-handler :participant-left-group (register-handler :participant-left-group
(u/side-effect! (u/side-effect!
@ -186,12 +208,16 @@
(register-handler :participant-invited-to-group (register-handler :participant-invited-to-group
(u/side-effect! (u/side-effect!
(fn [{:keys [current-public-key]} (fn [{:keys [current-public-key chats]}
[_ {:keys [from] [_ {:keys [from]
{:keys [group-id identity message-id]} :payload}]] {:keys [group-id identity message-id]} :payload}]]
(participant-invited-to-group-message group-id current-public-key identity from message-id) (let [admin (get-in chats [group-id :group-admin])]
(when-not (= current-public-key identity) (when (= from admin)
(dispatch [:add-contact-to-group! group-id identity]))))) (dispatch
[:received-message
(participant-invited-to-group-message group-id current-public-key identity from message-id)])
(when-not (= current-public-key identity)
(dispatch [:add-contact-to-group! group-id identity])))))))
(register-handler :add-contact-to-group! (register-handler :add-contact-to-group!
(u/side-effect! (u/side-effect!

View File

@ -12,10 +12,10 @@
(defn- decrypt [key content] (defn- decrypt [key content]
(try (try
(r/read-string (e/decrypt key content)) {:content (r/read-string (e/decrypt key content))}
(catch :default err (catch :default err
(log/warn :decrypt-error err) (debug :decrypt-error err)
nil))) {:error err})))
(defn- parse-content [key {:keys [content]} was-encrypted?] (defn- parse-content [key {:keys [content]} was-encrypted?]
(debug :parse-content (debug :parse-content
@ -23,7 +23,7 @@
"Content exists:" (not (nil? content))) "Content exists:" (not (nil? content)))
(if (and (not was-encrypted?) key content) (if (and (not was-encrypted?) key content)
(decrypt key content) (decrypt key content)
content)) {:content content}))
(defn message-listener (defn message-listener
[{:keys [web3 identity callback keypair]}] [{:keys [web3 identity callback keypair]}]
@ -42,9 +42,12 @@
(i/normalize-hex from)) (i/normalize-hex from))
;; allow user to receive his own discoveries ;; allow user to receive his own discoveries
(= type :discover)) (= type :discover))
(let [content (parse-content (:private keypair) payload' (not= "0x0" to)) (let [{:keys [content error]} (parse-content (:private keypair)
payload'' (assoc payload' :content content) payload'
(not= "0x0" to))]
message' (assoc message :payload payload'')] (if error
(callback (if ack? :ack type) message') (debug :failed-to-handle-message error)
(ack/check-ack! web3 from payload'' identity))))))) (let [payload'' (assoc payload' :content content)
message' (assoc message :payload payload'')]
(callback (if ack? :ack type) message')
(ack/check-ack! web3 from payload'' identity)))))))))