Merge lp:~phablet-team/messaging-framework/enable_message_broadcast into lp:messaging-framework
- enable_message_broadcast
- Merge into trunk
Proposed by
Gustavo Pichorim Boiko
Status: | Superseded |
---|---|
Proposed branch: | lp:~phablet-team/messaging-framework/enable_message_broadcast |
Merge into: | lp:messaging-framework |
Diff against target: |
1370 lines (+784/-115) 22 files modified
debian/changelog (+18/-0) include/messaging/broadcast.h (+45/-0) include/messaging/group.h (+15/-2) include/messaging/group_manager.h (+19/-10) include/messaging/has_interfaces.h (+5/-1) include/messaging/interface.h (+5/-0) include/messaging/qt/tp/interfaces/base_channel_subject.h (+88/-0) include/messaging/qt/tp/interfaces/base_channel_subject_internal.h (+59/-0) include/messaging/qt/tp/interfaces/channel_interface_roles_adaptor.h (+1/-0) include/messaging/qt/tp/interfaces/types.h (+2/-1) include/messaging/qt/tp/text_channel.h (+15/-5) include/messaging/recipient.h (+2/-1) src/CMakeLists.txt (+4/-0) src/messaging/broadcast.cpp (+37/-0) src/messaging/group.cpp (+37/-3) src/messaging/group_manager.cpp (+12/-6) src/messaging/has_interfaces.cpp (+9/-2) src/messaging/qt/tp/connection.cpp (+97/-62) src/messaging/qt/tp/interfaces/base_channel_roles.cpp (+1/-1) src/messaging/qt/tp/interfaces/base_channel_subject.cpp (+205/-0) src/messaging/qt/tp/text_channel.cpp (+104/-21) tests/mock_group_manager.h (+4/-0) |
To merge this branch: | bzr merge lp:~phablet-team/messaging-framework/enable_message_broadcast |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
system-apps-ci-bot | continuous-integration | Needs Fixing | |
Ubuntu Phablet Team | Pending | ||
Review via email: mp+306014@code.launchpad.net |
This proposal has been superseded by a proposal from 2016-09-17.
Commit message
Add a broadcast recipient type and make it possible to use broadcast text
channels.
Description of the change
Add a broadcast recipient type and make it possible to use broadcast text
channels.
To post a comment you must log in.
Revision history for this message
system-apps-ci-bot (system-apps-ci-bot) wrote : | # |
review:
Needs Fixing
(continuous-integration)
- 63. By Roberto Mier Escandon
-
merged prereq branch
- 64. By Gustavo Pichorim Boiko
-
Do not crash if the Roles interface is not available
- 65. By Gustavo Pichorim Boiko
-
Use an ID for the broadcast recipient.
- 66. By Roberto Mier Escandon
-
merged prereq lp:~phablet-team/messaging-framework/fix-roles-interface-event
- 67. By Roberto Mier Escandon
-
creating broadcast using group_starter, for it to have an initial id
Unmerged revisions
Preview Diff
[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1 | === modified file 'debian/changelog' |
2 | --- debian/changelog 2016-08-25 20:07:12 +0000 |
3 | +++ debian/changelog 2016-09-17 21:47:53 +0000 |
4 | @@ -1,3 +1,21 @@ |
5 | +messaging-framework (0.1-1ubuntu28) vivid; urgency=medium |
6 | + |
7 | + * Subject interface |
8 | + |
9 | + -- Roberto Mier Escandon <roberto.escandon@canonical.com> Wed, 14 Sep 2016 13:04:50 +0200 |
10 | + |
11 | +messaging-framework (0.1-1ubuntu27) vivid; urgency=medium |
12 | + |
13 | + * snapshot |
14 | + |
15 | + -- Roberto Mier Escandon <roberto.escandon@canonical.com> Tue, 13 Sep 2016 18:11:06 +0200 |
16 | + |
17 | +messaging-framework (0.1-1ubuntu26) vivid; urgency=medium |
18 | + |
19 | + * Group has additional properties if plugins want to add there their specific values |
20 | + |
21 | + -- Roberto Mier Escandon <roberto.escandon@canonical.com> Mon, 12 Sep 2016 17:01:04 +0200 |
22 | + |
23 | messaging-framework (0.1-1ubuntu25) vivid; urgency=medium |
24 | |
25 | * Fixed self handle included in members |
26 | |
27 | === added file 'include/messaging/broadcast.h' |
28 | --- include/messaging/broadcast.h 1970-01-01 00:00:00 +0000 |
29 | +++ include/messaging/broadcast.h 2016-09-17 21:47:53 +0000 |
30 | @@ -0,0 +1,45 @@ |
31 | +/* |
32 | + * Copyright © 2016 Canonical Ltd. |
33 | + * |
34 | + * This program is free software: you can redistribute it and/or modify it |
35 | + * under the terms of the GNU Lesser General Public License version 3, |
36 | + * as published by the Free Software Foundation. |
37 | + * |
38 | + * This program is distributed in the hope that it will be useful, |
39 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
40 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
41 | + * GNU Lesser General Public License for more details. |
42 | + * |
43 | + * You should have received a copy of the GNU Lesser General Public License |
44 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
45 | + */ |
46 | + |
47 | +#ifndef BROADCAST_H |
48 | +#define BROADCAST_H |
49 | + |
50 | +#include <messaging/recipient.h> |
51 | +#include <messaging/member.h> |
52 | +#include <messaging/members.h> |
53 | + |
54 | +namespace messaging |
55 | +{ |
56 | + |
57 | +class MESSAGING_FW_PUBLIC Broadcast : public Recipient |
58 | +{ |
59 | +public: |
60 | + Broadcast(const Members &members = Members{}); |
61 | + |
62 | + RecipientType type() const override; |
63 | + Members members() const; |
64 | + |
65 | + typedef std::shared_ptr<Broadcast> shared_ptr; |
66 | +private: |
67 | + /// @cond |
68 | + struct Private; |
69 | + std::shared_ptr<Private> impl; |
70 | + /// @endcond |
71 | +}; |
72 | + |
73 | +} |
74 | + |
75 | +#endif // BROADCAST_H |
76 | |
77 | === modified file 'include/messaging/group.h' |
78 | --- include/messaging/group.h 2016-08-17 13:25:23 +0000 |
79 | +++ include/messaging/group.h 2016-09-17 21:47:53 +0000 |
80 | @@ -27,15 +27,28 @@ |
81 | class MESSAGING_FW_PUBLIC Group : public Recipient |
82 | { |
83 | public: |
84 | + static const std::string ROOM_NAME; |
85 | + static const std::string DESCRIPTION; |
86 | + static const std::string SERVER; |
87 | + static const std::string CREATION_TIMESTAMP; |
88 | + static const std::string SUBJECT; |
89 | + |
90 | Group(std::string id, |
91 | const Members &initial_invitees = Members{}, |
92 | std::string initial_title = std::string{}, |
93 | - const std::shared_ptr<Member> &creator = std::make_shared<Member>(std::string{})); |
94 | - |
95 | + const std::shared_ptr<Member> &creator = std::make_shared<Member>(std::string{}), |
96 | + const VariantMap &additional_properties = VariantMap{}); |
97 | + |
98 | RecipientType type() const override; |
99 | + |
100 | Members initial_invitees() const; |
101 | std::string initial_title() const; |
102 | std::shared_ptr<Member> creator() const; |
103 | + VariantMap &additional_properties(); |
104 | + |
105 | + std::shared_ptr<Variant> additional_property(const std::string &key) const; |
106 | + void set_additional_property(const std::string &key, const std::shared_ptr<messaging::Variant> &value); |
107 | + bool exists_additional_property(const std::string &key) const; |
108 | |
109 | typedef std::shared_ptr<Group> shared_ptr; |
110 | private: |
111 | |
112 | === modified file 'include/messaging/group_manager.h' |
113 | --- include/messaging/group_manager.h 2016-08-25 11:04:57 +0000 |
114 | +++ include/messaging/group_manager.h 2016-09-17 21:47:53 +0000 |
115 | @@ -33,11 +33,12 @@ |
116 | // Maintain sequence of 2 multiples if adding new values to preserve flags management |
117 | enum class GroupPermissions : uint |
118 | { |
119 | - NoPermissions = 0, //0 |
120 | - CanChangeTitle = 1 << 0, //1 |
121 | - CanKick = 1 << 1, //2 |
122 | - CanSetAdmin = 1 << 2, //4 |
123 | - CanDissolve = 1 << 3 //8 |
124 | + NoPermissions = 0, //0 |
125 | + CanChangeTitle = 1 << 0, //1 |
126 | + CanKick = 1 << 1, //2 |
127 | + CanSetAdmin = 1 << 2, //4 |
128 | + CanDissolve = 1 << 3, //8 |
129 | + CanChangeSubject = 1 << 4 //16 |
130 | }; |
131 | |
132 | enum class CancelGroupReason |
133 | @@ -62,8 +63,9 @@ |
134 | |
135 | virtual void on_group_created() = 0; |
136 | virtual void on_group_cancelled(CancelGroupReason reason, const std::string &message) = 0; |
137 | - virtual void on_group_title_changed(const std::string& new_title, |
138 | - const Member& actor, |
139 | + virtual void on_group_title_changed(const std::string& new_title) = 0; |
140 | + virtual void on_group_subject_changed(const std::string& new_subject, |
141 | + const std::shared_ptr<Member>& actor, |
142 | const std::chrono::system_clock::time_point& when) = 0; |
143 | virtual void on_members_updated(const Members& members) = 0; |
144 | virtual void on_group_permissions_changed(const Flags<GroupPermissions> &permissions) = 0; |
145 | @@ -88,12 +90,18 @@ |
146 | /// @brief change_group_title modifies the title of the group |
147 | virtual void change_group_title(const std::string& title) = 0; |
148 | |
149 | + /// @brief change_group_subject modifies the subject of the group |
150 | + virtual void change_group_subject(const std::string& subject) = 0; |
151 | + |
152 | /// @brief group_id returns the id of the group being managed |
153 | virtual std::string group_id() = 0; |
154 | |
155 | /// @brief group_title returns the title of the group being managed |
156 | virtual std::string group_title() = 0; |
157 | |
158 | + /// @brief group_subject returns the subject of the group being managed |
159 | + virtual std::string group_subject() = 0; |
160 | + |
161 | /// @brief creator returns the creator of the group being managed |
162 | virtual std::shared_ptr<Member> group_creator() = 0; |
163 | |
164 | @@ -117,9 +125,10 @@ |
165 | |
166 | void announce_group_created(); |
167 | void announce_group_cancelled(CancelGroupReason reason, const std::string& message); |
168 | - void announce_group_title_changed(const std::string& new_title, |
169 | - const Member& actor = Member{std::string{}}, |
170 | - const std::chrono::system_clock::time_point& when = std::chrono::system_clock::now()); |
171 | + void announce_group_title_changed(const std::string& new_title); |
172 | + void announce_group_subject_changed(const std::string& new_subject, |
173 | + const std::shared_ptr<Member>& actor = std::make_shared<Member>(std::string{}), |
174 | + const std::chrono::system_clock::time_point& when = std::chrono::system_clock::now()); |
175 | void announce_members_updated(const Members& members); |
176 | void announce_group_permissions_changed(const Flags<GroupPermissions> &permissions); |
177 | |
178 | |
179 | === modified file 'include/messaging/has_interfaces.h' |
180 | --- include/messaging/has_interfaces.h 2016-03-30 19:19:19 +0000 |
181 | +++ include/messaging/has_interfaces.h 2016-09-17 21:47:53 +0000 |
182 | @@ -22,7 +22,7 @@ |
183 | namespace messaging |
184 | { |
185 | |
186 | -class MESSAGING_FW_PUBLIC HasInterfaces |
187 | +class MESSAGING_FW_PUBLIC HasInterfaces : public std::enable_shared_from_this<HasInterfaces> |
188 | { |
189 | public: |
190 | virtual ~HasInterfaces() = default; |
191 | @@ -51,6 +51,10 @@ |
192 | protected: |
193 | HasInterfaces(); |
194 | |
195 | + /// @brief on_interface_plugged overwrite this virtual method in subclasses if wanted to perform any action when |
196 | + /// certain interface is plugged |
197 | + virtual void on_interface_plugged(const std::shared_ptr<Interface>& interface); |
198 | + |
199 | private: |
200 | /// @cond |
201 | struct Private; |
202 | |
203 | === modified file 'include/messaging/interface.h' |
204 | --- include/messaging/interface.h 2016-03-30 19:19:19 +0000 |
205 | +++ include/messaging/interface.h 2016-09-17 21:47:53 +0000 |
206 | @@ -26,6 +26,7 @@ |
207 | namespace messaging |
208 | { |
209 | |
210 | +class HasInterfaces; |
211 | class Interface; |
212 | |
213 | typedef std::set<std::shared_ptr<Interface>, std::owner_less<std::shared_ptr<Interface>>> InterfacesSet; |
214 | @@ -34,6 +35,10 @@ |
215 | { |
216 | public: |
217 | virtual ~Interface() = default; |
218 | + |
219 | + /// @brief on_plugged executed when this interfaces is plugged to a host object. Overwrite this method |
220 | + /// in subclasses if wanted certain behaviour when plug happens. |
221 | + virtual void on_plugged(const std::weak_ptr<HasInterfaces> &where) = 0; |
222 | }; |
223 | |
224 | } |
225 | |
226 | === added file 'include/messaging/qt/tp/interfaces/base_channel_subject.h' |
227 | --- include/messaging/qt/tp/interfaces/base_channel_subject.h 1970-01-01 00:00:00 +0000 |
228 | +++ include/messaging/qt/tp/interfaces/base_channel_subject.h 2016-09-17 21:47:53 +0000 |
229 | @@ -0,0 +1,88 @@ |
230 | +/* |
231 | + * Copyright © 2016 Canonical Ltd. |
232 | + * |
233 | + * This program is free software: you can redistribute it and/or modify it |
234 | + * under the terms of the GNU Lesser General Public License version 3, |
235 | + * as published by the Free Software Foundation. |
236 | + * |
237 | + * This program is distributed in the hope that it will be useful, |
238 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
239 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
240 | + * GNU Lesser General Public License for more details. |
241 | + * |
242 | + * You should have received a copy of the GNU Lesser General Public License |
243 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
244 | + */ |
245 | + |
246 | +#ifndef MESSAGING_QT_TP_INTERFACES_BASE_CHANNEL_SUBJECT_H |
247 | +#define MESSAGING_QT_TP_INTERFACES_BASE_CHANNEL_SUBJECT_H |
248 | + |
249 | +#include <TelepathyQt/BaseChannel> |
250 | + |
251 | +#include <messaging/visibility.h> |
252 | + |
253 | +#include <messaging/qt/tp/interfaces/types.h> |
254 | + |
255 | +namespace messaging |
256 | +{ |
257 | +namespace qt |
258 | +{ |
259 | +namespace tp |
260 | +{ |
261 | +namespace interfaces |
262 | +{ |
263 | + |
264 | +class MESSAGING_FW_LOCAL BaseChannelSubjectInterface : public Tp::AbstractChannelInterface |
265 | +{ |
266 | + Q_OBJECT |
267 | + Q_DISABLE_COPY(BaseChannelSubjectInterface) |
268 | + |
269 | +public: |
270 | + static BaseChannelSubjectInterfacePtr create() { |
271 | + return BaseChannelSubjectInterfacePtr(new BaseChannelSubjectInterface()); |
272 | + } |
273 | + template<typename BaseChannelSubjectInterfaceSubclass> |
274 | + static Tp::SharedPtr<BaseChannelSubjectInterfaceSubclass> create() { |
275 | + return Tp::SharedPtr<BaseChannelSubjectInterfaceSubclass>( |
276 | + new BaseChannelSubjectInterfaceSubclass()); |
277 | + } |
278 | + virtual ~BaseChannelSubjectInterface(); |
279 | + |
280 | + QVariantMap immutableProperties() const; |
281 | + |
282 | + QString subject() const; |
283 | + void setSubject(const QString& subject); |
284 | + |
285 | + QString actor() const; |
286 | + void setActor(const QString &actor); |
287 | + |
288 | + uint actorHandle() const; |
289 | + void setActorHandle(uint handle); |
290 | + |
291 | + qlonglong timestamp() const; |
292 | + void setTimestamp(qlonglong timestamp); |
293 | + |
294 | + bool canSet() const; |
295 | + void setCanSet(bool canSet); |
296 | + |
297 | + typedef Tp::Callback2<void, const QString&, Tp::DBusError*> SetSubjectCallback; |
298 | + void setSetSubjectCallback(const SetSubjectCallback &cb); |
299 | + void setSubject(const QString &subject, Tp::DBusError *error); |
300 | + |
301 | +private: |
302 | + BaseChannelSubjectInterface(); |
303 | + void createAdaptor(); |
304 | + |
305 | + class Adaptee; |
306 | + friend class Adaptee; |
307 | + struct Private; |
308 | + friend struct Private; |
309 | + Private *mPriv; |
310 | +}; |
311 | + |
312 | + |
313 | +} |
314 | +} |
315 | +} |
316 | +} |
317 | +#endif // MESSAGING_QT_TP_INTERFACES_BASE_CHANNEL_SUBJECT_H |
318 | |
319 | === added file 'include/messaging/qt/tp/interfaces/base_channel_subject_internal.h' |
320 | --- include/messaging/qt/tp/interfaces/base_channel_subject_internal.h 1970-01-01 00:00:00 +0000 |
321 | +++ include/messaging/qt/tp/interfaces/base_channel_subject_internal.h 2016-09-17 21:47:53 +0000 |
322 | @@ -0,0 +1,59 @@ |
323 | +/* |
324 | + * Copyright © 2016 Canonical Ltd. |
325 | + * |
326 | + * This program is free software: you can redistribute it and/or modify it |
327 | + * under the terms of the GNU Lesser General Public License version 3, |
328 | + * as published by the Free Software Foundation. |
329 | + * |
330 | + * This program is distributed in the hope that it will be useful, |
331 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
332 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
333 | + * GNU Lesser General Public License for more details. |
334 | + * |
335 | + * You should have received a copy of the GNU Lesser General Public License |
336 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
337 | + */ |
338 | + |
339 | +#ifndef MESSAGING_QT_TP_INTERFACES_BASE_CHANNEL_SUBJECT_INTERNAL_H_ |
340 | +#define MESSAGING_QT_TP_INTERFACES_BASE_CHANNEL_SUBJECT_INTERNAL_H_ |
341 | + |
342 | +#include <TelepathyQt/_gen/svc-channel.h> |
343 | +#include <messaging/qt/tp/interfaces/base_channel_subject.h> |
344 | +#include <messaging/visibility.h> |
345 | + |
346 | +namespace messaging |
347 | +{ |
348 | +namespace qt |
349 | +{ |
350 | +namespace tp |
351 | +{ |
352 | +namespace interfaces |
353 | +{ |
354 | + |
355 | +class MESSAGING_FW_LOCAL BaseChannelSubjectInterface::Adaptee : public QObject |
356 | +{ |
357 | + Q_OBJECT |
358 | +public: |
359 | + Adaptee(BaseChannelSubjectInterface *interface); |
360 | + ~Adaptee(); |
361 | + |
362 | + QString subject() const; |
363 | + QString actor() const; |
364 | + uint actorHandle() const; |
365 | + qlonglong timestamp() const; |
366 | + bool canSet() const; |
367 | + |
368 | +public Q_SLOTS: |
369 | + void setSubject(const QString &subject, const Tp::Service::ChannelInterfaceSubjectAdaptor::SetSubjectContextPtr &context); |
370 | + |
371 | +public: |
372 | + BaseChannelSubjectInterface *mInterface; |
373 | +}; |
374 | + |
375 | +} |
376 | +} |
377 | +} |
378 | +} |
379 | + |
380 | +#endif // MESSAGING_QT_TP_INTERFACES_BASE_CHANNEL_SUBJECT_INTERNAL_H_ |
381 | + |
382 | |
383 | === modified file 'include/messaging/qt/tp/interfaces/channel_interface_roles_adaptor.h' |
384 | --- include/messaging/qt/tp/interfaces/channel_interface_roles_adaptor.h 2016-08-11 21:39:57 +0000 |
385 | +++ include/messaging/qt/tp/interfaces/channel_interface_roles_adaptor.h 2016-09-17 21:47:53 +0000 |
386 | @@ -13,6 +13,7 @@ |
387 | * You should have received a copy of the GNU Lesser General Public License |
388 | * along with this program. If not, see <http://www.gnu.org/licenses/>. |
389 | */ |
390 | + |
391 | #ifndef MESSAGING_QT_TP_INTERFACES_CHANNEL_INTERFACE_ROLES_ADAPTOR_H |
392 | #define MESSAGING_QT_TP_INTERFACES_CHANNEL_INTERFACE_ROLES_ADAPTOR_H |
393 | |
394 | |
395 | === modified file 'include/messaging/qt/tp/interfaces/types.h' |
396 | --- include/messaging/qt/tp/interfaces/types.h 2016-08-16 16:23:42 +0000 |
397 | +++ include/messaging/qt/tp/interfaces/types.h 2016-09-17 21:47:53 +0000 |
398 | @@ -33,10 +33,11 @@ |
399 | |
400 | class BaseChannelDestroyableInterface; |
401 | class BaseChannelRolesInterface; |
402 | +class BaseChannelSubjectInterface; |
403 | |
404 | typedef Tp::SharedPtr<BaseChannelDestroyableInterface> BaseChannelDestroyableInterfacePtr; |
405 | typedef Tp::SharedPtr<BaseChannelRolesInterface> BaseChannelRolesInterfacePtr; |
406 | - |
407 | +typedef Tp::SharedPtr<BaseChannelSubjectInterface> BaseChannelSubjectInterfacePtr; |
408 | |
409 | /** |
410 | * \struct HandleRolesMap |
411 | |
412 | === modified file 'include/messaging/qt/tp/text_channel.h' |
413 | --- include/messaging/qt/tp/text_channel.h 2016-08-30 18:46:08 +0000 |
414 | +++ include/messaging/qt/tp/text_channel.h 2016-09-17 21:47:53 +0000 |
415 | @@ -23,6 +23,7 @@ |
416 | |
417 | #include <messaging/qt/tp/interfaces/base_channel_destroyable.h> |
418 | #include <messaging/qt/tp/interfaces/base_channel_roles.h> |
419 | +#include <messaging/qt/tp/interfaces/base_channel_subject.h> |
420 | #include <messaging/qt/tp/interfaces/types.h> |
421 | #include <messaging/qt/tp/interfaces/constants.h> |
422 | |
423 | @@ -81,8 +82,11 @@ |
424 | void on_group_cancelled(CancelGroupReason reason, const std::string &message) override; |
425 | |
426 | /// @brief on_group_title_changed when group title has changed in the server |
427 | - void on_group_title_changed(const std::string& new_title, |
428 | - const Member& actor, |
429 | + void on_group_title_changed(const std::string& new_title) override; |
430 | + |
431 | + /// @brief on_group_subject_changed when group title has changed in the server |
432 | + void on_group_subject_changed(const std::string& new_subject, |
433 | + const std::shared_ptr<Member>& actor, |
434 | const std::chrono::system_clock::time_point& when) override; |
435 | |
436 | /// @brief on_members_updated when group members have changed (added/removed) in server |
437 | @@ -148,9 +152,12 @@ |
438 | void on_group_cancelled(CancelGroupReason reason, const std::string &message) override; |
439 | |
440 | /// @brief on_group_title_changed when group title has changed in the server |
441 | - void on_group_title_changed(const std::string& new_title, |
442 | - const Member& actor, |
443 | - const std::chrono::system_clock::time_point& when) override; |
444 | + void on_group_title_changed(const std::string& new_title) override; |
445 | + |
446 | + /// @brief on_group_subject_changed when group title has changed in the server |
447 | + void on_group_subject_changed(const std::string& new_subject, |
448 | + const std::shared_ptr<Member>& actor, |
449 | + const std::chrono::system_clock::time_point& when) override; |
450 | |
451 | /// @brief on_members_updated when group members have changed (added/removed) in server |
452 | void on_members_updated(const Members& members) override; |
453 | @@ -192,6 +199,8 @@ |
454 | void update_group_configuration(const QVariantMap &properties, Tp::DBusError *error); |
455 | // Handler action to update roles for current channel group members |
456 | void update_roles(const interfaces::HandleRolesMap &contact_roles, Tp::DBusError *error); |
457 | + // Handle action to update current channel subject |
458 | + void set_subject(const QString &subject, Tp::DBusError *error); |
459 | |
460 | // channel destruction request. only supported in group chats |
461 | void destroy(Tp::DBusError* error); |
462 | @@ -211,6 +220,7 @@ |
463 | Tp::BaseChannelChatStateInterfacePtr chat_state_interface; |
464 | interfaces::BaseChannelDestroyableInterfacePtr destroyable_interface; |
465 | interfaces::BaseChannelRolesInterfacePtr roles_interface; |
466 | + interfaces::BaseChannelSubjectInterfacePtr subject_interface; |
467 | |
468 | // NOTE(rmescandon): this is a temporal member in the class not needed from Telepathy Qt >= 0.9.7.0 which |
469 | // includes Tp::BaseChannel::connection() method to obtain it whenever is needed. |
470 | |
471 | === modified file 'include/messaging/recipient.h' |
472 | --- include/messaging/recipient.h 2016-03-30 19:19:19 +0000 |
473 | +++ include/messaging/recipient.h 2016-09-17 21:47:53 +0000 |
474 | @@ -26,7 +26,8 @@ |
475 | enum RecipientType |
476 | { |
477 | user, ///< the peer is a user |
478 | - group ///< the peer is a group |
479 | + group, ///< the peer is a group |
480 | + broadcast ///< the peer is a broadcast group |
481 | }; |
482 | |
483 | class MESSAGING_FW_PUBLIC Recipient |
484 | |
485 | === modified file 'src/CMakeLists.txt' |
486 | --- src/CMakeLists.txt 2016-08-26 14:11:06 +0000 |
487 | +++ src/CMakeLists.txt 2016-09-17 21:47:53 +0000 |
488 | @@ -9,6 +9,8 @@ |
489 | ${CMAKE_SOURCE_DIR}/include/messaging/qt/tp/interfaces/base_channel_destroyable_internal.h |
490 | ${CMAKE_SOURCE_DIR}/include/messaging/qt/tp/interfaces/base_channel_roles.h |
491 | ${CMAKE_SOURCE_DIR}/include/messaging/qt/tp/interfaces/base_channel_roles_internal.h |
492 | + ${CMAKE_SOURCE_DIR}/include/messaging/qt/tp/interfaces/base_channel_subject.h |
493 | + ${CMAKE_SOURCE_DIR}/include/messaging/qt/tp/interfaces/base_channel_subject_internal.h |
494 | ${CMAKE_SOURCE_DIR}/include/messaging/qt/tp/interfaces/channel_interface_roles_adaptor.h) |
495 | |
496 | set( |
497 | @@ -16,6 +18,7 @@ |
498 | |
499 | messaging/associative_connector_factory.cpp |
500 | messaging/boost/variant.cpp |
501 | + messaging/broadcast.cpp |
502 | messaging/chat.cpp |
503 | messaging/group.cpp |
504 | messaging/group_manager.cpp |
505 | @@ -48,6 +51,7 @@ |
506 | |
507 | messaging/qt/tp/interfaces/base_channel_destroyable.cpp |
508 | messaging/qt/tp/interfaces/base_channel_roles.cpp |
509 | + messaging/qt/tp/interfaces/base_channel_subject.cpp |
510 | messaging/qt/tp/interfaces/channel_interface_roles_adaptor.cpp |
511 | |
512 | messaging/runner.cpp |
513 | |
514 | === added file 'src/messaging/broadcast.cpp' |
515 | --- src/messaging/broadcast.cpp 1970-01-01 00:00:00 +0000 |
516 | +++ src/messaging/broadcast.cpp 2016-09-17 21:47:53 +0000 |
517 | @@ -0,0 +1,37 @@ |
518 | +/* |
519 | + * Copyright © 2016 Canonical Ltd. |
520 | + * |
521 | + * This program is free software: you can redistribute it and/or modify it |
522 | + * under the terms of the GNU Lesser General Public License version 3, |
523 | + * as published by the Free Software Foundation. |
524 | + * |
525 | + * This program is distributed in the hope that it will be useful, |
526 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
527 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
528 | + * GNU Lesser General Public License for more details. |
529 | + * |
530 | + * You should have received a copy of the GNU Lesser General Public License |
531 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
532 | + */ |
533 | + |
534 | +#include <messaging/broadcast.h> |
535 | + |
536 | +struct messaging::Broadcast::Private |
537 | +{ |
538 | + messaging::Members members; |
539 | +}; |
540 | + |
541 | +messaging::Broadcast::Broadcast(const messaging::Members &members) |
542 | + : Recipient{std::string{}}, impl{new Private{members}} |
543 | +{ |
544 | +} |
545 | + |
546 | +messaging::RecipientType messaging::Broadcast::type() const |
547 | +{ |
548 | + return messaging::RecipientType::broadcast; |
549 | +} |
550 | + |
551 | +messaging::Members messaging::Broadcast::members() const |
552 | +{ |
553 | + return impl->members; |
554 | +} |
555 | |
556 | === modified file 'src/messaging/group.cpp' |
557 | --- src/messaging/group.cpp 2016-08-17 13:25:23 +0000 |
558 | +++ src/messaging/group.cpp 2016-09-17 21:47:53 +0000 |
559 | @@ -16,15 +16,24 @@ |
560 | |
561 | #include <messaging/group.h> |
562 | |
563 | +#include <messaging/qt/variant.h> |
564 | + |
565 | +const std::string messaging::Group::ROOM_NAME = "roomName"; |
566 | +const std::string messaging::Group::DESCRIPTION = "description"; |
567 | +const std::string messaging::Group::SERVER = "server"; |
568 | +const std::string messaging::Group::CREATION_TIMESTAMP = "creationTimestamp"; |
569 | +const std::string messaging::Group::SUBJECT = "subject"; |
570 | + |
571 | struct messaging::Group::Private |
572 | { |
573 | messaging::Members initial_invitees; |
574 | std::string initial_title; |
575 | std::shared_ptr<messaging::Member> creator; |
576 | + messaging::VariantMap additional_properties; |
577 | }; |
578 | |
579 | -messaging::Group::Group(std::string id, const messaging::Members &initial_invitees, std::string initial_title, const std::shared_ptr<Member> &creator) |
580 | - : Recipient{id}, impl{new Private{initial_invitees, initial_title, creator}} |
581 | +messaging::Group::Group(std::string id, const messaging::Members &initial_invitees, std::string initial_title, const std::shared_ptr<Member> &creator, const VariantMap &additional_properties) |
582 | + : Recipient{id}, impl{new Private{initial_invitees, initial_title, creator, additional_properties}} |
583 | { |
584 | } |
585 | |
586 | @@ -45,5 +54,30 @@ |
587 | |
588 | std::shared_ptr<messaging::Member> messaging::Group::creator() const |
589 | { |
590 | - return impl->creator; |
591 | + return impl->creator; |
592 | +} |
593 | + |
594 | +messaging::VariantMap &messaging::Group::additional_properties() |
595 | +{ |
596 | + return impl->additional_properties; |
597 | +} |
598 | + |
599 | +std::shared_ptr<messaging::Variant> messaging::Group::additional_property(const std::string &key) const |
600 | +{ |
601 | + auto it = impl->additional_properties.find(key); |
602 | + if (it != impl->additional_properties.end()) { |
603 | + return it->second; |
604 | + } |
605 | + return std::make_shared<messaging::qt::Variant>(QVariant{}); |
606 | +} |
607 | + |
608 | +void messaging::Group::set_additional_property(const std::string &key, const std::shared_ptr<messaging::Variant> &value) |
609 | +{ |
610 | + impl->additional_properties[key] = value; |
611 | +} |
612 | + |
613 | +bool messaging::Group::exists_additional_property(const std::string &key) const |
614 | +{ |
615 | + auto it = impl->additional_properties.find(key); |
616 | + return it != impl->additional_properties.end(); |
617 | } |
618 | |
619 | === modified file 'src/messaging/group_manager.cpp' |
620 | --- src/messaging/group_manager.cpp 2016-08-25 11:04:57 +0000 |
621 | +++ src/messaging/group_manager.cpp 2016-09-17 21:47:53 +0000 |
622 | @@ -64,12 +64,18 @@ |
623 | impl->observer->on_group_cancelled(reason, message); |
624 | } |
625 | |
626 | -void messaging::GroupManager::announce_group_title_changed(const std::string &new_title, |
627 | - const Member &actor, |
628 | - const std::chrono::system_clock::time_point &when) |
629 | -{ |
630 | - validate_observer(); |
631 | - impl->observer->on_group_title_changed(new_title, actor, when); |
632 | +void messaging::GroupManager::announce_group_title_changed(const std::string &new_title) |
633 | +{ |
634 | + validate_observer(); |
635 | + impl->observer->on_group_title_changed(new_title); |
636 | +} |
637 | + |
638 | +void messaging::GroupManager::announce_group_subject_changed(const std::string &new_subject, |
639 | + const std::shared_ptr<Member> &actor, |
640 | + const std::chrono::system_clock::time_point &when) |
641 | +{ |
642 | + validate_observer(); |
643 | + impl->observer->on_group_subject_changed(new_subject, actor, when); |
644 | } |
645 | |
646 | void messaging::GroupManager::announce_members_updated(const Members& members) |
647 | |
648 | === modified file 'src/messaging/has_interfaces.cpp' |
649 | --- src/messaging/has_interfaces.cpp 2016-03-30 19:19:19 +0000 |
650 | +++ src/messaging/has_interfaces.cpp 2016-09-17 21:47:53 +0000 |
651 | @@ -36,5 +36,12 @@ |
652 | void messaging::HasInterfaces::plug_interface(const std::shared_ptr<Interface>& interface) |
653 | { |
654 | impl->interfaces.insert(interface); |
655 | -} |
656 | - |
657 | + |
658 | + interface->on_plugged(shared_from_this()); |
659 | + on_interface_plugged(interface); |
660 | +} |
661 | + |
662 | +void messaging::HasInterfaces::on_interface_plugged(const std::shared_ptr<Interface> &/*interface*/) |
663 | +{ |
664 | + // left empty on purpose |
665 | +} |
666 | |
667 | === modified file 'src/messaging/qt/tp/connection.cpp' |
668 | --- src/messaging/qt/tp/connection.cpp 2016-08-24 21:51:07 +0000 |
669 | +++ src/messaging/qt/tp/connection.cpp 2016-09-17 21:47:53 +0000 |
670 | @@ -22,6 +22,7 @@ |
671 | #include <messaging/qt/tp/interfaces/base_channel_destroyable.h> |
672 | #include <messaging/qt/tp/interfaces/base_channel_roles.h> |
673 | |
674 | +#include <messaging/broadcast.h> |
675 | #include <messaging/message.h> |
676 | #include <messaging/presence_status_not_supported.h> |
677 | #include <messaging/user.h> |
678 | @@ -593,7 +594,6 @@ |
679 | { |
680 | std::shared_ptr<GroupStarter> group_starter = connection->group_starter(); |
681 | group_manager = group_starter->accept_group(group); |
682 | - |
683 | if (group_manager->group_id().empty()) |
684 | { |
685 | LOG(ERROR) << "Group creation rejected"; |
686 | @@ -601,14 +601,20 @@ |
687 | return Tp::BaseChannelPtr{}; |
688 | } |
689 | |
690 | - // update recipient with id, title and members |
691 | + // update recipient with id, title, creator, members and additional properties |
692 | + // FIXME(rmescandon): a refactor is needed to move all this to a group_manager->group() object |
693 | + // and create a copy constructor for Group which can be populated with cached data when needed |
694 | + auto additional_properties = group->additional_properties(); |
695 | + if (not group_manager->group_subject().empty()) { |
696 | + additional_properties[Group::SUBJECT] = std::make_shared<messaging::BoostVariant>(group_manager->group_subject()); |
697 | + } |
698 | auto members = group_manager->members(); |
699 | recipient = std::make_shared<messaging::Group>( |
700 | group_manager->group_id(), |
701 | members, |
702 | group_manager->group_title(), |
703 | - group_manager->group_creator()); |
704 | - |
705 | + group_manager->group_creator(), |
706 | + additional_properties); |
707 | } |
708 | catch (const std::exception &e) |
709 | { |
710 | @@ -650,13 +656,20 @@ |
711 | return Tp::BaseChannelPtr{}; |
712 | } |
713 | |
714 | - // update recipient with id, title and members |
715 | + // update recipient with id, title, creator, members and additional properties |
716 | + // FIXME(rmescandon): a refactor is needed to move all this to a group_manager->group() object |
717 | + // and create a copy constructor for Group which can be populated with cached data when needed |
718 | + auto additional_properties = group->additional_properties(); |
719 | + if (not group_manager->group_subject().empty()) { |
720 | + additional_properties[Group::SUBJECT] = std::make_shared<messaging::BoostVariant>(group_manager->group_subject()); |
721 | + } |
722 | auto members = group_manager->members(); |
723 | recipient = std::make_shared<messaging::Group>( |
724 | group_manager->group_id(), |
725 | members, |
726 | group_manager->group_title(), |
727 | - group_manager->group_creator()); |
728 | + group_manager->group_creator(), |
729 | + additional_properties); |
730 | } |
731 | catch (const std::exception &e) |
732 | { |
733 | @@ -673,11 +686,15 @@ |
734 | break; |
735 | } |
736 | case Tp::HandleTypeNone: { |
737 | - // This is the case of creating a group from the app. There is not type for the handle of the channel to be created when |
738 | + bool is_room = hints.contains(TP_QT_IFACE_CHANNEL_INTERFACE_ROOM + QLatin1String(".RoomName")); |
739 | + |
740 | + // There are two possible cases in which handle type is going to be none: chat rooms and broadcast channels. |
741 | + // For broadcast channels the handle type will remain as none during the entire channel lifetime. For chat rooms |
742 | + // once the creation is finished, the type will change to room. |
743 | + // For the chat room case, this code will be called when creating a group from the app. |
744 | + // There is not type for the handle of the channel to be created when |
745 | // received the request. We have to switch to Room type and get the provided information |
746 | - |
747 | messaging::Members initial_invitees; |
748 | - std::string title; |
749 | if (hints.contains(TP_QT_IFACE_CHANNEL_INTERFACE_CONFERENCE + QLatin1String(".InitialInviteeIDs"))) |
750 | { |
751 | QStringList initial_invitees_ids = |
752 | @@ -698,73 +715,91 @@ |
753 | //FIXME: get contact attribute display name for the user second param |
754 | //FIXME: consider here if needed to provide initial roles to members |
755 | initial_invitees.push_back(std::make_shared<Member>(normalized_id, |
756 | - PendingStatus::Remote, |
757 | + is_room ? PendingStatus::Remote : PendingStatus::None, |
758 | Flags<Role>(Role::Member), |
759 | std::string{}/* display_name*/ )); |
760 | } |
761 | } |
762 | |
763 | - if (hints.contains(TP_QT_IFACE_CHANNEL_INTERFACE_ROOM_CONFIG + QLatin1String(".Title"))) |
764 | - { |
765 | - title = hints[TP_QT_IFACE_CHANNEL_INTERFACE_ROOM_CONFIG + QLatin1String(".Title")].toString().toStdString(); |
766 | - } |
767 | - |
768 | // check if the client requested a chat room |
769 | - if (hints.contains(TP_QT_IFACE_CHANNEL_INTERFACE_ROOM + QLatin1String(".RoomName"))) |
770 | + // if so, create the group related stuff |
771 | + if (is_room) |
772 | { |
773 | target_handle_type = Tp::HandleTypeRoom; |
774 | - } |
775 | - |
776 | - std::string initiator_handle; |
777 | - if (hints.contains(TP_QT_IFACE_CHANNEL + QLatin1String(".InitiatorHandle"))) |
778 | - { |
779 | - initiator_handle = hints[TP_QT_IFACE_CHANNEL + QLatin1String(".InitiatorHandle")].toString().toStdString(); |
780 | - } |
781 | - |
782 | - //FIXME: fill group title parameter when got somehow |
783 | - // create initial group recipient with no identifier for plugin to create the group |
784 | - recipient = std::make_shared<messaging::Group>( |
785 | - std::string{} /* no id exists yet */, |
786 | - initial_invitees, |
787 | - title, |
788 | - std::make_shared<messaging::Member>(initiator_handle)); |
789 | - |
790 | - try |
791 | - { |
792 | - std::shared_ptr<GroupStarter> group_starter = connection->group_starter(); |
793 | - messaging::Group::shared_ptr group = std::dynamic_pointer_cast<messaging::Group>(recipient); |
794 | - group_manager = group_starter->create_group(group); |
795 | - |
796 | - if (group_manager->group_id().empty()) |
797 | + |
798 | + std::string title; |
799 | + auto additional_properties = VariantMap{}; |
800 | + |
801 | + if (hints.contains(TP_QT_IFACE_CHANNEL_INTERFACE_ROOM_CONFIG + QLatin1String(".Title"))) |
802 | + { |
803 | + title = hints[TP_QT_IFACE_CHANNEL_INTERFACE_ROOM_CONFIG + QLatin1String(".Title")].toString().toStdString(); |
804 | + } |
805 | + |
806 | + std::string initiator_handle; |
807 | + if (hints.contains(TP_QT_IFACE_CHANNEL + QLatin1String(".InitiatorHandle"))) |
808 | + { |
809 | + initiator_handle = hints[TP_QT_IFACE_CHANNEL + QLatin1String(".InitiatorHandle")].toString().toStdString(); |
810 | + } |
811 | + |
812 | + if (hints.contains(TP_QT_IFACE_CHANNEL_INTERFACE_SUBJECT + QLatin1String(".Subject"))) |
813 | + { |
814 | + additional_properties[Group::SUBJECT] = |
815 | + std::make_shared<messaging::BoostVariant>( |
816 | + hints[TP_QT_IFACE_CHANNEL_INTERFACE_SUBJECT + QLatin1String(".Subject")].toString().toStdString()); |
817 | + } |
818 | + |
819 | + // create initial group recipient with no identifier for plugin to create the group |
820 | + recipient = std::make_shared<messaging::Group>( |
821 | + std::string{} /* no id exists yet */, |
822 | + initial_invitees, |
823 | + title, |
824 | + std::make_shared<messaging::Member>(initiator_handle), |
825 | + additional_properties); |
826 | + try |
827 | + { |
828 | + std::shared_ptr<GroupStarter> group_starter = connection->group_starter(); |
829 | + messaging::Group::shared_ptr group = std::dynamic_pointer_cast<messaging::Group>(recipient); |
830 | + group_manager = group_starter->create_group(group); |
831 | + |
832 | + if (group_manager->group_id().empty()) |
833 | + { |
834 | + LOG(ERROR) << "Group creation rejected"; |
835 | + error->set(TP_QT_ERROR_CANCELLED, "Group creation rejected"); |
836 | + return Tp::BaseChannelPtr{}; |
837 | + } |
838 | + |
839 | + // update recipient with id, title, members and additional properties |
840 | + auto additional_properties = group->additional_properties(); |
841 | + if (not group_manager->group_subject().empty()) { |
842 | + additional_properties[Group::SUBJECT] = std::make_shared<messaging::BoostVariant>(group_manager->group_subject()); |
843 | + } |
844 | + recipient = std::make_shared<messaging::Group>( |
845 | + group_manager->group_id(), |
846 | + group_manager->members(), |
847 | + group_manager->group_title(), |
848 | + group_manager->group_creator(), |
849 | + additional_properties); |
850 | + } |
851 | + catch (const std::exception &e) |
852 | + { |
853 | + LOG(ERROR) << "Group creation rejected, " << e.what(); |
854 | + error->set(TP_QT_ERROR_CANCELLED, "Group creation rejected"); |
855 | + return Tp::BaseChannelPtr{}; |
856 | + } |
857 | + catch (...) |
858 | { |
859 | LOG(ERROR) << "Group creation rejected"; |
860 | error->set(TP_QT_ERROR_CANCELLED, "Group creation rejected"); |
861 | return Tp::BaseChannelPtr{}; |
862 | } |
863 | |
864 | - // update recipient with id, title and members |
865 | - recipient = std::make_shared<messaging::Group>( |
866 | - group_manager->group_id(), |
867 | - group_manager->members(), |
868 | - group_manager->group_title(), |
869 | - group_manager->group_creator()); |
870 | - } |
871 | - catch (const std::exception &e) |
872 | - { |
873 | - LOG(ERROR) << "Group creation rejected, " << e.what(); |
874 | - error->set(TP_QT_ERROR_CANCELLED, "Group creation rejected"); |
875 | - return Tp::BaseChannelPtr{}; |
876 | - } |
877 | - catch (...) |
878 | - { |
879 | - LOG(ERROR) << "Group creation rejected"; |
880 | - error->set(TP_QT_ERROR_CANCELLED, "Group creation rejected"); |
881 | - return Tp::BaseChannelPtr{}; |
882 | - } |
883 | - |
884 | - // request handle from group_manager id, filled with the group id after calling start_group() |
885 | - Tp::DBusError error; |
886 | - target_handle = request_handles(Tp::HandleTypeRoom, QStringList() << QString::fromStdString(group_manager->group_id()), &error)[0]; |
887 | + // request handle from group_manager id, filled with the group id after calling start_group() |
888 | + Tp::DBusError error; |
889 | + target_handle = request_handles(Tp::HandleTypeRoom, QStringList() << QString::fromStdString(group_manager->group_id()), &error)[0]; |
890 | + } else { |
891 | + // if not, consider this a broadcast channel |
892 | + recipient = std::make_shared<messaging::Broadcast>(initial_invitees); |
893 | + } |
894 | break; |
895 | } |
896 | default: |
897 | |
898 | === modified file 'src/messaging/qt/tp/interfaces/base_channel_roles.cpp' |
899 | --- src/messaging/qt/tp/interfaces/base_channel_roles.cpp 2016-08-12 13:19:22 +0000 |
900 | +++ src/messaging/qt/tp/interfaces/base_channel_roles.cpp 2016-09-17 21:47:53 +0000 |
901 | @@ -148,7 +148,7 @@ |
902 | } |
903 | |
904 | if (!canUpdateRoles()) { |
905 | - error->set(TP_QT_ERROR_PERMISSION_DENIED, QLatin1String("Operation not allowed; anUpdateRoles flag set to false")); |
906 | + error->set(TP_QT_ERROR_PERMISSION_DENIED, QLatin1String("Operation not allowed; canUpdateRoles flag set to false")); |
907 | } |
908 | |
909 | return mPriv->updateRolesCB(contactRoles, error); |
910 | |
911 | === added file 'src/messaging/qt/tp/interfaces/base_channel_subject.cpp' |
912 | --- src/messaging/qt/tp/interfaces/base_channel_subject.cpp 1970-01-01 00:00:00 +0000 |
913 | +++ src/messaging/qt/tp/interfaces/base_channel_subject.cpp 2016-09-17 21:47:53 +0000 |
914 | @@ -0,0 +1,205 @@ |
915 | +/* |
916 | + * Copyright © 2016 Canonical Ltd. |
917 | + * |
918 | + * This program is free software: you can redistribute it and/or modify it |
919 | + * under the terms of the GNU Lesser General Public License version 3, |
920 | + * as published by the Free Software Foundation. |
921 | + * |
922 | + * This program is distributed in the hope that it will be useful, |
923 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
924 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
925 | + * GNU Lesser General Public License for more details. |
926 | + * |
927 | + * You should have received a copy of the GNU Lesser General Public License |
928 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
929 | + */ |
930 | + |
931 | +#include <TelepathyQt/DBusObject> |
932 | +#include <messaging/qt/tp/interfaces/base_channel_subject.h> |
933 | +#include <messaging/qt/tp/interfaces/base_channel_subject_internal.h> |
934 | + |
935 | +namespace mqti = messaging::qt::tp::interfaces; |
936 | + |
937 | +// Chan.I.Subject |
938 | +mqti::BaseChannelSubjectInterface::Adaptee::Adaptee(BaseChannelSubjectInterface *interface) |
939 | + : QObject(interface), |
940 | + mInterface(interface) |
941 | +{ |
942 | +} |
943 | + |
944 | +mqti::BaseChannelSubjectInterface::Adaptee::~Adaptee() |
945 | +{ |
946 | +} |
947 | + |
948 | +struct TP_QT_NO_EXPORT mqti::BaseChannelSubjectInterface::Private { |
949 | + Private(BaseChannelSubjectInterface *parent) |
950 | + :adaptee(new BaseChannelSubjectInterface::Adaptee(parent)) { |
951 | + } |
952 | + |
953 | + QString subject; |
954 | + QString actor; |
955 | + uint actorHandle; |
956 | + qlonglong timestamp; |
957 | + bool canSet; |
958 | + SetSubjectCallback setSubjectCB; |
959 | + BaseChannelSubjectInterface::Adaptee *adaptee; |
960 | +}; |
961 | + |
962 | +QString mqti::BaseChannelSubjectInterface::Adaptee::subject() const |
963 | +{ |
964 | + return mInterface->subject(); |
965 | +} |
966 | + |
967 | +QString mqti::BaseChannelSubjectInterface::Adaptee::actor() const |
968 | +{ |
969 | + return mInterface->actor(); |
970 | +} |
971 | + |
972 | +uint mqti::BaseChannelSubjectInterface::Adaptee::actorHandle() const |
973 | +{ |
974 | + return mInterface->actorHandle(); |
975 | +} |
976 | + |
977 | +qlonglong mqti::BaseChannelSubjectInterface::Adaptee::timestamp() const |
978 | +{ |
979 | + return mInterface->timestamp(); |
980 | +} |
981 | + |
982 | +bool mqti::BaseChannelSubjectInterface::Adaptee::canSet() const |
983 | +{ |
984 | + return mInterface->canSet(); |
985 | +} |
986 | + |
987 | +void mqti::BaseChannelSubjectInterface::Adaptee::setSubject(const QString &subject, const Tp::Service::ChannelInterfaceSubjectAdaptor::SetSubjectContextPtr &context) |
988 | +{ |
989 | + if (!mInterface->mPriv->setSubjectCB.isValid()) { |
990 | + context->setFinishedWithError(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); |
991 | + return; |
992 | + } |
993 | + |
994 | + Tp::DBusError error; |
995 | + mInterface->mPriv->setSubjectCB(subject, &error); |
996 | + if (error.isValid()) { |
997 | + context->setFinishedWithError(error.name(), error.message()); |
998 | + return; |
999 | + } |
1000 | + context->setFinished(); |
1001 | +} |
1002 | + |
1003 | +/** |
1004 | + * \class BaseChannelSubjectInterface |
1005 | + * |
1006 | + * \brief Base class for implementations of Channel.Interface.Subject |
1007 | + * |
1008 | + */ |
1009 | + |
1010 | +/** |
1011 | + * Class constructor. |
1012 | + */ |
1013 | +mqti::BaseChannelSubjectInterface::BaseChannelSubjectInterface() |
1014 | + : Tp::AbstractChannelInterface(TP_QT_IFACE_CHANNEL_INTERFACE_SUBJECT), |
1015 | + mPriv(new Private(this)) |
1016 | +{ |
1017 | +} |
1018 | + |
1019 | +void mqti::BaseChannelSubjectInterface::setSetSubjectCallback(const SetSubjectCallback &cb) |
1020 | +{ |
1021 | + mPriv->setSubjectCB = cb; |
1022 | +} |
1023 | + |
1024 | +/** |
1025 | + * Class destructor. |
1026 | + */ |
1027 | +mqti::BaseChannelSubjectInterface::~BaseChannelSubjectInterface() |
1028 | +{ |
1029 | + delete mPriv; |
1030 | +} |
1031 | + |
1032 | +/** |
1033 | + * Return the immutable properties of this interface. |
1034 | + * |
1035 | + * Immutable properties cannot change after the interface has been registered |
1036 | + * on a service on the bus with registerInterface(). |
1037 | + * |
1038 | + * \return The immutable properties of this interface. |
1039 | + */ |
1040 | +QVariantMap mqti::BaseChannelSubjectInterface::immutableProperties() const |
1041 | +{ |
1042 | + QVariantMap map; |
1043 | + return map; |
1044 | +} |
1045 | + |
1046 | +void mqti::BaseChannelSubjectInterface::createAdaptor() |
1047 | +{ |
1048 | + (void) new Tp::Service::ChannelInterfaceSubjectAdaptor(dbusObject()->dbusConnection(), |
1049 | + mPriv->adaptee, dbusObject()); |
1050 | +} |
1051 | + |
1052 | +void mqti::BaseChannelSubjectInterface::setSubject(const QString &subject, Tp::DBusError *error) |
1053 | +{ |
1054 | + if (!mPriv->setSubjectCB.isValid()) { |
1055 | + error->set(TP_QT_ERROR_NOT_IMPLEMENTED, QLatin1String("Not implemented")); |
1056 | + return; |
1057 | + } |
1058 | + |
1059 | + if (!canSet()) { |
1060 | + error->set(TP_QT_ERROR_PERMISSION_DENIED, QLatin1String("Operation not allowed; canSet flag set to false")); |
1061 | + } |
1062 | + |
1063 | + return mPriv->setSubjectCB(subject, error); |
1064 | +} |
1065 | + |
1066 | +QString mqti::BaseChannelSubjectInterface::subject() const |
1067 | +{ |
1068 | + return mPriv->subject; |
1069 | +} |
1070 | + |
1071 | +void mqti::BaseChannelSubjectInterface::setSubject(const QString &subject) |
1072 | +{ |
1073 | + mPriv->subject = subject; |
1074 | + notifyPropertyChanged(QLatin1String("Subject"), QVariant::fromValue(subject)); |
1075 | +} |
1076 | + |
1077 | +QString mqti::BaseChannelSubjectInterface::actor() const |
1078 | +{ |
1079 | + return mPriv->actor; |
1080 | +} |
1081 | + |
1082 | +void mqti::BaseChannelSubjectInterface::setActor(const QString &actor) |
1083 | +{ |
1084 | + mPriv->actor = actor; |
1085 | + notifyPropertyChanged(QLatin1String("Actor"), QVariant::fromValue(actor)); |
1086 | +} |
1087 | + |
1088 | +uint mqti::BaseChannelSubjectInterface::actorHandle() const |
1089 | +{ |
1090 | + return mPriv->actorHandle; |
1091 | +} |
1092 | + |
1093 | +void mqti::BaseChannelSubjectInterface::setActorHandle(uint handle) |
1094 | +{ |
1095 | + mPriv->actorHandle = handle; |
1096 | + notifyPropertyChanged(QLatin1String("ActorHandle"), QVariant::fromValue(handle)); |
1097 | +} |
1098 | + |
1099 | +qlonglong mqti::BaseChannelSubjectInterface::timestamp() const |
1100 | +{ |
1101 | + return mPriv->timestamp; |
1102 | +} |
1103 | + |
1104 | +void mqti::BaseChannelSubjectInterface::setTimestamp(qlonglong timestamp) |
1105 | +{ |
1106 | + mPriv->timestamp = timestamp; |
1107 | + notifyPropertyChanged(QLatin1String("Timestamp"), QVariant::fromValue(timestamp)); |
1108 | +} |
1109 | + |
1110 | +bool mqti::BaseChannelSubjectInterface::canSet() const |
1111 | +{ |
1112 | + return mPriv->canSet; |
1113 | +} |
1114 | + |
1115 | +void mqti::BaseChannelSubjectInterface::setCanSet(bool canSet) |
1116 | +{ |
1117 | + mPriv->canSet = canSet; |
1118 | + notifyPropertyChanged(QLatin1String("CanSet"), QVariant::fromValue(canSet)); |
1119 | +} |
1120 | |
1121 | === modified file 'src/messaging/qt/tp/text_channel.cpp' |
1122 | --- src/messaging/qt/tp/text_channel.cpp 2016-08-30 18:46:08 +0000 |
1123 | +++ src/messaging/qt/tp/text_channel.cpp 2016-09-17 21:47:53 +0000 |
1124 | @@ -21,6 +21,7 @@ |
1125 | |
1126 | #include <messaging/qt/variant.h> |
1127 | |
1128 | +#include <messaging/broadcast.h> |
1129 | #include <messaging/connection.h> |
1130 | #include <messaging/group.h> |
1131 | #include <messaging/messenger.h> |
1132 | @@ -181,13 +182,21 @@ |
1133 | }); |
1134 | } |
1135 | |
1136 | -void mqt::tp::TextChannel::Observer::on_group_title_changed(const std::string &new_title, |
1137 | - const Member& actor, |
1138 | - const std::chrono::system_clock::time_point& when) |
1139 | -{ |
1140 | - auto thiz = shared_from_this(); |
1141 | - runtime->enter_with_task([thiz, new_title, actor, when]() { |
1142 | - thiz->tc->on_group_title_changed(new_title, actor, when); |
1143 | +void mqt::tp::TextChannel::Observer::on_group_title_changed(const std::string &new_title) |
1144 | +{ |
1145 | + auto thiz = shared_from_this(); |
1146 | + runtime->enter_with_task([thiz, new_title]() { |
1147 | + thiz->tc->on_group_title_changed(new_title); |
1148 | + }); |
1149 | +} |
1150 | + |
1151 | +void mqt::tp::TextChannel::Observer::on_group_subject_changed(const std::string &new_subject, |
1152 | + const std::shared_ptr<Member>& actor, |
1153 | + const std::chrono::system_clock::time_point& when) |
1154 | +{ |
1155 | + auto thiz = shared_from_this(); |
1156 | + runtime->enter_with_task([thiz, new_subject, actor, when]() { |
1157 | + thiz->tc->on_group_subject_changed(new_subject, actor, when); |
1158 | }); |
1159 | } |
1160 | |
1161 | @@ -322,6 +331,27 @@ |
1162 | return; |
1163 | } |
1164 | |
1165 | + // NOTE (rmescandon): Build and populate values for Subject interface before than roomConfig one. This is needed for having |
1166 | + // available subject Actor before setting the title in room config. That way, same value could be taken as actor for subject |
1167 | + // and title in upper layers |
1168 | + subject_interface = interfaces::BaseChannelSubjectInterface::create(); |
1169 | + subject_interface->setActor(QString::fromStdString(group->creator()->id())); |
1170 | + subject_interface->setActorHandle(creator_handle); |
1171 | + subject_interface->setTimestamp(static_cast<qlonglong>(std::chrono::system_clock::to_time_t(std::chrono::system_clock::now()))); |
1172 | + |
1173 | + try |
1174 | + { |
1175 | + subject_interface->setCanSet(group_manager->permissions().is_set(GroupPermissions::CanChangeSubject)); |
1176 | + // the last thing to set is the subject itself. This way, all the properties should be available in client |
1177 | + // for composing all the information like "%Actor% set subject to %Subject%" |
1178 | + subject_interface->setSubject(QString::fromStdString(group_manager->group_subject())); |
1179 | + } |
1180 | + catch (...) |
1181 | + { |
1182 | + LOG(ERROR) << "An exception has been thrown when setting group title as channel subject"; |
1183 | + return; |
1184 | + } |
1185 | + |
1186 | // uncomment the following code when room name is part of messaging::Group |
1187 | //QString roomName = QString::fromStdString(group->id()); |
1188 | room_interface = Tp::BaseChannelRoomInterface::create(/* roomName */ QString(), |
1189 | @@ -343,8 +373,8 @@ |
1190 | |
1191 | room_config_interface->setConfigurationRetrieved(true); |
1192 | |
1193 | - // FIXME (rmescandon): as telepathy does not offer a way to differentiate whether it can be changed one configuration element |
1194 | - // or other, let's use the flag to enable/dissable all configuration properties permissions by now |
1195 | + // As telepathy does not offer a way to differentiate whether it can be changed one configuration element |
1196 | + // or other, let's use the flag to enable/dissable all configuration properties permissions |
1197 | room_config_interface->setCanUpdateConfiguration(group_manager->permissions().is_set(GroupPermissions::CanChangeTitle)); |
1198 | |
1199 | // FIXME: check what flags we want by default |
1200 | @@ -366,6 +396,24 @@ |
1201 | // we need to set the initial group members |
1202 | on_members_updated(group->initial_invitees()); |
1203 | } |
1204 | + else if (recipient->type() == RecipientType::broadcast) |
1205 | + { |
1206 | + messaging::Broadcast::shared_ptr broadcast = std::dynamic_pointer_cast<messaging::Broadcast>(recipient); |
1207 | + // for broadcast channels we just need to plug the group interface with limited capabilities |
1208 | + Tp::ChannelGroupFlags groupFlags = Tp::ChannelGroupFlagHandleOwnersNotAvailable | |
1209 | + Tp::ChannelGroupFlagMembersChangedDetailed | |
1210 | + Tp::ChannelGroupFlagProperties; |
1211 | + group_interface = Tp::BaseChannelGroupInterface::create(); |
1212 | + group_interface->setGroupFlags(groupFlags); |
1213 | + |
1214 | + // we need to plug this interface here to avoid a crash |
1215 | + plug_interface_if_available(group_interface); |
1216 | + |
1217 | + destroyable_interface = mqt::tp::interfaces::BaseChannelDestroyableInterface::create(); |
1218 | + |
1219 | + // we need to set the initial group members |
1220 | + on_members_updated(broadcast->members()); |
1221 | + } |
1222 | |
1223 | chat_state_interface = Tp::BaseChannelChatStateInterface::create(); |
1224 | |
1225 | @@ -588,7 +636,6 @@ |
1226 | LOG(ERROR) << "An exception has been thrown when setting group self handle"; |
1227 | return; |
1228 | } |
1229 | - |
1230 | } |
1231 | |
1232 | void mqt::tp::TextChannel::close_channel_with_reason(uint reason, const QString &message) |
1233 | @@ -662,22 +709,42 @@ |
1234 | close_channel_with_reason(reason, message); |
1235 | } |
1236 | |
1237 | -void mqt::tp::TextChannel::on_group_title_changed(const std::string &new_title, |
1238 | - const Member& actor, |
1239 | - const std::chrono::system_clock::time_point& when) |
1240 | +void mqt::tp::TextChannel::on_group_title_changed(const std::string &new_title) |
1241 | { |
1242 | - //TODO(rmescandon): must be implemented interface Subject2 in order to use parameters actor and when |
1243 | - // (see https://telepathy.freedesktop.org/spec/Channel_Interface_Subject.html) |
1244 | - // meanwhile they are unused |
1245 | - Q_UNUSED(actor); |
1246 | - Q_UNUSED(when); |
1247 | - |
1248 | + // for a flexible management in client, set as title both room_config title and subject |
1249 | if (room_config_interface) |
1250 | { |
1251 | room_config_interface->setTitle(QString::fromStdString(new_title)); |
1252 | } |
1253 | } |
1254 | |
1255 | +void mqt::tp::TextChannel::on_group_subject_changed(const std::string &new_subject, |
1256 | + const std::shared_ptr<Member>& actor, |
1257 | + const std::chrono::system_clock::time_point& when) |
1258 | +{ |
1259 | + if (subject_interface) |
1260 | + { |
1261 | + if (not actor->id().empty()) |
1262 | + { |
1263 | + Tp::DBusError error; |
1264 | + uint handle; |
1265 | + if (actor->id() == "me") { |
1266 | + handle = tp_connection->selfHandle(); |
1267 | + } else { |
1268 | + handle = tp_connection->requestHandles(Tp::HandleTypeContact, QStringList() << QString::fromStdString(actor->id()), &error)[0]; |
1269 | + } |
1270 | + // set always the actor before the subject, for having it available in client when subject is available |
1271 | + subject_interface->setActor(QString::fromStdString(actor->id())); |
1272 | + subject_interface->setActorHandle(handle); |
1273 | + } |
1274 | + |
1275 | + subject_interface->setTimestamp(static_cast<qlonglong>(std::chrono::system_clock::to_time_t(when))); |
1276 | + // the last thing to set is the subject itself. This way, all the properties should be available in client |
1277 | + // for composing all the information like "%Actor% set subject to %Subject%" |
1278 | + subject_interface->setSubject(QString::fromStdString(new_subject)); |
1279 | + } |
1280 | +} |
1281 | + |
1282 | void mqt::tp::TextChannel::on_members_updated(const Members& received_members) |
1283 | { |
1284 | LOG(INFO) << __PRETTY_FUNCTION__; |
1285 | @@ -778,6 +845,11 @@ |
1286 | room_config_interface->setCanUpdateConfiguration(permissions.is_set(GroupPermissions::CanChangeTitle)); |
1287 | } |
1288 | |
1289 | + if (not subject_interface.isNull()) |
1290 | + { |
1291 | + subject_interface->setCanSet(permissions.is_set(GroupPermissions::CanChangeTitle)); |
1292 | + } |
1293 | + |
1294 | // Can kick other participants? |
1295 | if (not group_interface.isNull()) |
1296 | { |
1297 | @@ -966,6 +1038,11 @@ |
1298 | return; |
1299 | } |
1300 | |
1301 | + set_subject(properties["Title"].toString(), error); |
1302 | +} |
1303 | + |
1304 | +void mqt::tp::TextChannel::set_subject(const QString &subject, Tp::DBusError *error) |
1305 | +{ |
1306 | try |
1307 | { |
1308 | std::shared_ptr<messaging::GroupManager> group_manager = chat->interface<GroupManager>(); |
1309 | @@ -979,11 +1056,11 @@ |
1310 | return; |
1311 | } |
1312 | |
1313 | - group_manager->change_group_title(properties["Title"].toString().toStdString()); |
1314 | + group_manager->change_group_title(subject.toStdString()); |
1315 | } |
1316 | catch (...) |
1317 | { |
1318 | - LOG(ERROR) << "An exception has been thrown when updating group configuration"; |
1319 | + LOG(ERROR) << "An exception has been thrown when setting subject"; |
1320 | } |
1321 | } |
1322 | |
1323 | @@ -1081,6 +1158,11 @@ |
1324 | { |
1325 | roles_interface->setUpdateRolesCallback(Tp::memFun(this, &TextChannel::update_roles)); |
1326 | } |
1327 | + |
1328 | + if (!subject_interface.isNull()) |
1329 | + { |
1330 | + subject_interface->setSetSubjectCallback(Tp::memFun(this, &TextChannel::set_subject)); |
1331 | + } |
1332 | } |
1333 | |
1334 | void mqt::tp::TextChannel::plug_interfaces_once() |
1335 | @@ -1092,6 +1174,7 @@ |
1336 | plug_interface_if_available(chat_state_interface); |
1337 | plug_interface_if_available(destroyable_interface); |
1338 | plug_interface_if_available(roles_interface); |
1339 | + plug_interface_if_available(subject_interface); |
1340 | } |
1341 | |
1342 | void mqt::tp::TextChannel::plug_interface_if_available(const Tp::AbstractChannelInterfacePtr &interface) |
1343 | |
1344 | === modified file 'tests/mock_group_manager.h' |
1345 | --- tests/mock_group_manager.h 2016-08-17 15:04:16 +0000 |
1346 | +++ tests/mock_group_manager.h 2016-09-17 21:47:53 +0000 |
1347 | @@ -34,19 +34,23 @@ |
1348 | MOCK_METHOD1(on_group_created, void(const std::string& id)); |
1349 | MOCK_METHOD0(on_group_cancelled, void()); |
1350 | MOCK_METHOD1(on_group_title_changed, void(const std::string&)); |
1351 | + MOCK_METHOD3(on_group_subject_changed, void(const std::string&, const std::shared_ptr<messaging::Member>&, const std::chrono::system_clock::time_point&)); |
1352 | }; |
1353 | |
1354 | MOCK_METHOD0(leave_group, void()); |
1355 | MOCK_METHOD0(dissolve_group, void()); |
1356 | MOCK_METHOD0(join_group, void()); |
1357 | MOCK_METHOD1(change_group_title, void(const std::string&)); |
1358 | + MOCK_METHOD1(change_group_subject, void(const std::string&)); |
1359 | MOCK_METHOD1(add_members, void(const messaging::Members&)); |
1360 | MOCK_METHOD1(remove_members, void(const messaging::Members&)); |
1361 | MOCK_METHOD0(group_id, std::string()); |
1362 | MOCK_METHOD0(group_title, std::string()); |
1363 | + MOCK_METHOD0(group_subject, std::string()); |
1364 | MOCK_METHOD0(group_creator, std::shared_ptr<messaging::Member>()); |
1365 | MOCK_METHOD0(members, messaging::Members()); |
1366 | MOCK_METHOD1(set_observer, void(const std::shared_ptr<Observer>&)); |
1367 | + MOCK_METHOD1(on_plugged, void(const std::weak_ptr<messaging::HasInterfaces>&)); |
1368 | }; |
1369 | |
1370 | } |
FAILED: Continuous integration, rev:62 /jenkins. canonical. com/system- apps/job/ lp-messaging- framework- ci/75/ /jenkins. canonical. com/system- apps/job/ build/1541/ console /jenkins. canonical. com/system- apps/job/ build-0- fetch/1541 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= vivid+overlay/ 1389 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= vivid+overlay/ 1389/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= xenial+ overlay/ 1389 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= xenial+ overlay/ 1389/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= yakkety/ 1389 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=amd64, release= yakkety/ 1389/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= vivid+overlay/ 1389 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= vivid+overlay/ 1389/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 1389 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= xenial+ overlay/ 1389/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= yakkety/ 1389 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=armhf, release= yakkety/ 1389/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= vivid+overlay/ 1389 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= vivid+overlay/ 1389/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= xenial+ overlay/ 1389 /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= xenial+ overlay/ 1389/artifact/ output/ *zip*/output. zip /jenkins. canonical. com/system- apps/job/ build-2- binpkg/ arch=i386, release= yakkety/ 1389/console
https:/
Executed test runs:
FAILURE: https:/
SUCCESS: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
SUCCESS: https:/
deb: https:/
FAILURE: https:/
Click here to trigger a rebuild: /jenkins. canonical. com/system- apps/job/ lp-messaging- framework- ci/75/rebuild
https:/