;
} else if (group.myMembership === 'join' && this.state.editing) {
const leaveButtonTooltip = this.state.isUserPrivileged ?
- _t("You are a member of this community") :
- _t("You are an administrator of this community");
+ _t("You are an administrator of this community") :
+ _t("You are a member of this community");
const leaveButtonClasses = classnames({
"mx_RoomHeader_textButton": true,
"mx_GroupView_textButton": true,
@@ -790,7 +815,7 @@ export default React.createClass({
_getMemberSettingsSection: function() {
return
diff --git a/src/groups.js b/src/groups.js
index 69871c45e9..06db5d067f 100644
--- a/src/groups.js
+++ b/src/groups.js
@@ -43,5 +43,9 @@ export function groupRoomFromApiObject(apiObject) {
roomId: apiObject.room_id,
canonicalAlias: apiObject.canonical_alias,
avatarUrl: apiObject.avatar_url,
+ topic: apiObject.topic,
+ numJoinedMembers: apiObject.num_joined_members,
+ worldReadable: apiObject.world_readable,
+ guestCanJoin: apiObject.guest_can_join,
};
}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index cf6ee70ddf..9a79227961 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -54,8 +54,6 @@
"Room name or alias": "Room name or alias",
"Add to community": "Add to community",
"Failed to invite the following users to %(groupId)s:": "Failed to invite the following users to %(groupId)s:",
- "Invites sent": "Invites sent",
- "Your community invitations have been sent.": "Your community invitations have been sent.",
"Failed to invite users to community": "Failed to invite users to community",
"Failed to invite users to %(groupId)s": "Failed to invite users to %(groupId)s",
"Failed to add the following rooms to %(groupId)s:": "Failed to add the following rooms to %(groupId)s:",
@@ -154,8 +152,10 @@
"%(widgetName)s widget removed by %(senderName)s": "%(widgetName)s widget removed by %(senderName)s",
"Communities": "Communities",
"Message Pinning": "Message Pinning",
+ "Mention": "Mention",
"%(displayName)s is typing": "%(displayName)s is typing",
"%(names)s and one other are typing": "%(names)s and one other are typing",
+ "%(names)s and %(count)s others are typing|other": "%(names)s and %(count)s others are typing",
"%(names)s and %(lastPerson)s are typing": "%(names)s and %(lastPerson)s are typing",
"Failure to create room": "Failure to create room",
"Server may be unavailable, overloaded, or you hit a bug.": "Server may be unavailable, overloaded, or you hit a bug.",
@@ -240,6 +240,7 @@
"Unignore": "Unignore",
"Ignore": "Ignore",
"Jump to read receipt": "Jump to read receipt",
+ "Invite": "Invite",
"User Options": "User Options",
"Direct chats": "Direct chats",
"Unmute": "Unmute",
@@ -451,6 +452,7 @@
"You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?": "You are about to be taken to a third-party site so you can authenticate your account for use with %(integrationsUrl)s. Do you wish to continue?",
"Removed or unknown message type": "Removed or unknown message type",
"Message removed by %(userId)s": "Message removed by %(userId)s",
+ "Message removed": "Message removed",
"Robot check is currently unavailable on desktop - please use a web browser": "Robot check is currently unavailable on desktop - please use a web browser",
"This Home Server would like to make sure you are not a robot": "This Home Server would like to make sure you are not a robot",
"Sign in with CAS": "Sign in with CAS",
@@ -495,10 +497,13 @@
"Are you sure you want to remove '%(roomName)s' from %(groupId)s?": "Are you sure you want to remove '%(roomName)s' from %(groupId)s?",
"Removing a room from the community will also remove it from the community page.": "Removing a room from the community will also remove it from the community page.",
"Remove": "Remove",
+ "Remove this room from the community": "Remove this room from the community",
"Unknown Address": "Unknown Address",
"NOTE: Apps are not end-to-end encrypted": "NOTE: Apps are not end-to-end encrypted",
"Do you want to load widget from URL:": "Do you want to load widget from URL:",
"Allow": "Allow",
+ "Delete Widget": "Delete Widget",
+ "Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?": "Deleting a widget removes it for all users in this room. Are you sure you want to delete this widget?",
"Delete widget": "Delete widget",
"Revoke widget access": "Revoke widget access",
"Edit": "Edit",
@@ -566,6 +571,7 @@
"Custom level": "Custom level",
"Room directory": "Room directory",
"Start chat": "Start chat",
+ "And %(count)s more...|other": "And %(count)s more...",
"ex. @bob:example.com": "ex. @bob:example.com",
"Add User": "Add User",
"Something went wrong!": "Something went wrong!",
@@ -584,7 +590,7 @@
"Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.": "Are you sure you wish to remove (delete) this event? Note that if you delete a room name or topic change, it could undo the change.",
"%(actionVerb)s this person?": "%(actionVerb)s this person?",
"Community IDs may only contain alphanumeric characters": "Community IDs may only contain alphanumeric characters",
- "Room creation failed": "Room creation failed",
+ "Something went wrong whilst creating your community": "Something went wrong whilst creating your community",
"Create Community": "Create Community",
"Community Name": "Community Name",
"Example": "Example",
@@ -677,17 +683,17 @@
"Leave %(groupName)s?": "Leave %(groupName)s?",
"Leave": "Leave",
"Unable to leave room": "Unable to leave room",
+ "Community Settings": "Community Settings",
"Add rooms to this community": "Add rooms to this community",
"Featured Rooms:": "Featured Rooms:",
"Featured Users:": "Featured Users:",
"%(inviter)s has invited you to join this community": "%(inviter)s has invited you to join this community",
- "You are a member of this community": "You are a member of this community",
"You are an administrator of this community": "You are an administrator of this community",
+ "You are a member of this community": "You are a member of this community",
"Community Member Settings": "Community Member Settings",
"Publish this community on your profile": "Publish this community on your profile",
"Long Description (HTML)": "Long Description (HTML)",
"Description": "Description",
- "Community Settings": "Community Settings",
"Community %(groupId)s not found": "Community %(groupId)s not found",
"This Home server does not support communities": "This Home server does not support communities",
"Failed to load %(groupId)s": "Failed to load %(groupId)s",
@@ -753,6 +759,7 @@
"Disable Emoji suggestions while typing": "Disable Emoji suggestions while typing",
"Hide avatars in user and room mentions": "Hide avatars in user and room mentions",
"Disable big emoji in chat": "Disable big emoji in chat",
+ "Mirror local video feed": "Mirror local video feed",
"Opt out of analytics": "Opt out of analytics",
"Disable Peer-to-Peer for 1:1 calls": "Disable Peer-to-Peer for 1:1 calls",
"Never send encrypted messages to unverified devices from this device": "Never send encrypted messages to unverified devices from this device",
diff --git a/src/stores/FlairStore.js b/src/stores/FlairStore.js
index f9d9af75a9..1ac518a4f6 100644
--- a/src/stores/FlairStore.js
+++ b/src/stores/FlairStore.js
@@ -56,6 +56,10 @@ class FlairStore extends EventEmitter {
return groupSupport;
}
+ invalidatePublicisedGroups(userId) {
+ delete this._userGroups[userId];
+ }
+
getPublicisedGroupsCached(matrixClient, userId) {
if (this._userGroups[userId]) {
return Promise.resolve(this._userGroups[userId]);
diff --git a/src/stores/GroupStore.js b/src/stores/GroupStore.js
index c1ef4619cd..66bc293b44 100644
--- a/src/stores/GroupStore.js
+++ b/src/stores/GroupStore.js
@@ -15,6 +15,8 @@ limitations under the License.
*/
import EventEmitter from 'events';
+import { groupMemberFromApiObject, groupRoomFromApiObject } from '../groups';
+import FlairStore from './FlairStore';
/**
* Stores the group summary for a room and provides an API to change it and
@@ -27,8 +29,36 @@ export default class GroupStore extends EventEmitter {
this._matrixClient = matrixClient;
this._summary = {};
this._rooms = [];
- this._fetchSummary();
- this._fetchRooms();
+
+ this.on('error', (err) => {
+ console.error(`GroupStore for ${this.groupId} encountered error`, err);
+ });
+ }
+
+ _fetchMembers() {
+ this._matrixClient.getGroupUsers(this.groupId).then((result) => {
+ this._members = result.chunk.map((apiMember) => {
+ return groupMemberFromApiObject(apiMember);
+ });
+ this._notifyListeners();
+ }).catch((err) => {
+ console.error("Failed to get group member list: " + err);
+ this.emit('error', err);
+ });
+
+ this._matrixClient.getGroupInvitedUsers(this.groupId).then((result) => {
+ this._invitedMembers = result.chunk.map((apiMember) => {
+ return groupMemberFromApiObject(apiMember);
+ });
+ this._notifyListeners();
+ }).catch((err) => {
+ // Invited users not visible to non-members
+ if (err.httpStatus === 403) {
+ return;
+ }
+ console.error("Failed to get group invited member list: " + err);
+ this.emit('error', err);
+ });
}
_fetchSummary() {
@@ -42,7 +72,9 @@ export default class GroupStore extends EventEmitter {
_fetchRooms() {
this._matrixClient.getGroupRooms(this.groupId).then((resp) => {
- this._rooms = resp.chunk;
+ this._rooms = resp.chunk.map((apiRoom) => {
+ return groupRoomFromApiObject(apiRoom);
+ });
this._notifyListeners();
}).catch((err) => {
this.emit('error', err);
@@ -53,6 +85,17 @@ export default class GroupStore extends EventEmitter {
this.emit('update');
}
+ registerListener(fn) {
+ this.on('update', fn);
+ this._fetchSummary();
+ this._fetchRooms();
+ this._fetchMembers();
+ }
+
+ unregisterListener(fn) {
+ this.removeListener('update', fn);
+ }
+
getSummary() {
return this._summary;
}
@@ -61,6 +104,14 @@ export default class GroupStore extends EventEmitter {
return this._rooms;
}
+ getGroupMembers( ) {
+ return this._members;
+ }
+
+ getGroupInvitedMembers( ) {
+ return this._invitedMembers;
+ }
+
getGroupPublicity() {
return this._summary.user ? this._summary.user.is_publicised : null;
}
@@ -83,6 +134,11 @@ export default class GroupStore extends EventEmitter {
.then(this._fetchRooms.bind(this));
}
+ inviteUserToGroup(userId) {
+ return this._matrixClient.inviteUserToGroup(this.groupId, userId)
+ .then(this._fetchMembers.bind(this));
+ }
+
addRoomToGroupSummary(roomId, categoryId) {
return this._matrixClient
.addRoomToGroupSummary(this.groupId, roomId, categoryId)
@@ -110,6 +166,7 @@ export default class GroupStore extends EventEmitter {
setGroupPublicity(isPublished) {
return this._matrixClient
.setGroupPublicity(this.groupId, isPublished)
+ .then(() => { FlairStore.invalidatePublicisedGroups(this._matrixClient.credentials.userId); })
.then(this._fetchSummary.bind(this));
}
}
diff --git a/src/stores/GroupStoreCache.js b/src/stores/GroupStoreCache.js
index 551b155615..df5ffcda5e 100644
--- a/src/stores/GroupStoreCache.js
+++ b/src/stores/GroupStoreCache.js
@@ -33,8 +33,7 @@ class GroupStoreCache {
}
}
-let singletonGroupStoreCache = null;
-if (!singletonGroupStoreCache) {
- singletonGroupStoreCache = new GroupStoreCache();
+if (global.singletonGroupStoreCache === undefined) {
+ global.singletonGroupStoreCache = new GroupStoreCache();
}
-module.exports = singletonGroupStoreCache;
+export default global.singletonGroupStoreCache;
diff --git a/src/stores/RoomViewStore.js b/src/stores/RoomViewStore.js
index 795345242e..0a8eca8797 100644
--- a/src/stores/RoomViewStore.js
+++ b/src/stores/RoomViewStore.js
@@ -72,6 +72,13 @@ class RoomViewStore extends Store {
case 'view_room':
this._viewRoom(payload);
break;
+ case 'view_my_groups':
+ case 'view_group':
+ this._setState({
+ roomId: null,
+ roomAlias: null,
+ });
+ break;
case 'view_room_error':
this._viewRoomError(payload);
break;
diff --git a/src/utils/MultiInviter.js b/src/utils/MultiInviter.js
index e090f3d9e2..02c413ac83 100644
--- a/src/utils/MultiInviter.js
+++ b/src/utils/MultiInviter.js
@@ -18,6 +18,7 @@ limitations under the License.
import MatrixClientPeg from '../MatrixClientPeg';
import {getAddressType} from '../UserAddress';
import {inviteToRoom} from '../RoomInvite';
+import GroupStoreCache from '../stores/GroupStoreCache';
import Promise from 'bluebird';
/**
@@ -117,7 +118,9 @@ export default class MultiInviter {
let doInvite;
if (this.groupId !== null) {
- doInvite = MatrixClientPeg.get().inviteUserToGroup(this.groupId, addr);
+ doInvite = GroupStoreCache
+ .getGroupStore(MatrixClientPeg.get(), this.groupId)
+ .inviteUserToGroup(addr);
} else {
doInvite = inviteToRoom(this.roomId, addr);
}
diff --git a/test/components/views/elements/MemberEventListSummary-test.js b/test/components/views/elements/MemberEventListSummary-test.js
index 1618fe4cfe..436133c717 100644
--- a/test/components/views/elements/MemberEventListSummary-test.js
+++ b/test/components/views/elements/MemberEventListSummary-test.js
@@ -88,6 +88,9 @@ describe('MemberEventListSummary', function() {
sandbox = testUtils.stubClient();
languageHandler.setLanguage('en').done(done);
+ languageHandler.setMissingEntryGenerator(function(key) {
+ return key.split('|', 2)[1];
+ });
});
afterEach(function() {