Add option to add existing room in space
authorAjay Bura <ajbura@gmail.com>
Wed, 23 Feb 2022 14:00:48 +0000 (19:30 +0530)
committerAjay Bura <ajbura@gmail.com>
Wed, 23 Feb 2022 14:00:48 +0000 (19:30 +0530)
Signed-off-by: Ajay Bura <ajbura@gmail.com>
src/app/molecules/space-add-existing/SpaceAddExisting.jsx
src/util/matrixUtil.js

index 5bbb1da555c0c5cb14b4ce2ac72cacb7673d4a01..01de3b1c429f712d8162b9c808dba8161f185a0f 100644 (file)
@@ -7,7 +7,7 @@ import { twemojify } from '../../../util/twemojify';
 import initMatrix from '../../../client/initMatrix';
 import cons from '../../../client/state/cons';
 import navigation from '../../../client/state/navigation';
-import { joinRuleToIconSrc } from '../../../util/matrixUtil';
+import { joinRuleToIconSrc, getIdServer, genRoomVia } from '../../../util/matrixUtil';
 import { Debounce } from '../../../util/common';
 
 import Text from '../../atoms/text/Text';
@@ -23,7 +23,10 @@ import Dialog from '../dialog/Dialog';
 import CrossIC from '../../../../public/res/ic/outlined/cross.svg';
 import SearchIC from '../../../../public/res/ic/outlined/search.svg';
 
+import { useStore } from '../../hooks/useStore';
+
 function SpaceAddExistingContent({ roomId }) {
+  const mountStore = useStore(roomId);
   const [debounce] = useState(new Debounce());
   const [process, setProcess] = useState(null);
   const [selected, setSelected] = useState([]);
@@ -75,6 +78,26 @@ function SpaceAddExistingContent({ roomId }) {
 
   const handleAdd = async () => {
     setProcess(`Adding ${selected.length} items...`);
+
+    const promises = selected.map((rId) => {
+      const room = mx.getRoom(rId);
+      const via = genRoomVia(room);
+      if (via.length === 0) {
+        via.push(getIdServer(rId));
+      }
+
+      return mx.sendStateEvent(roomId, 'm.space.child', {
+        auto_join: false,
+        suggested: false,
+        via,
+      }, rId);
+    });
+
+    mountStore.setItem(true);
+    await Promise.allSettled(promises);
+    if (mountStore.getItem() !== true) return;
+    setSelected([]);
+    setProcess(null);
   };
 
   return (
index f52117b62d5eb6b5d9bc6d6645d5523874d85ed6..78d5bb8eddbbbdf3e73046d6061e2509115777e2 100644 (file)
@@ -9,7 +9,7 @@ import SpaceLockIC from '../../public/res/ic/outlined/space-lock.svg';
 
 const WELL_KNOWN_URI = '/.well-known/matrix/client';
 
-async function getBaseUrl(servername) {
+export async function getBaseUrl(servername) {
   let protocol = 'https://';
   if (servername.match(/^https?:\/\//) !== null) protocol = '';
   const serverDiscoveryUrl = `${protocol}${servername}${WELL_KNOWN_URI}`;
@@ -24,7 +24,7 @@ async function getBaseUrl(servername) {
   }
 }
 
-function getUsername(userId) {
+export function getUsername(userId) {
   const mx = initMatrix.matrixClient;
   const user = mx.getUser(userId);
   if (user === null) return userId;
@@ -35,11 +35,11 @@ function getUsername(userId) {
   return username;
 }
 
-function getUsernameOfRoomMember(roomMember) {
+export function getUsernameOfRoomMember(roomMember) {
   return roomMember.name || roomMember.userId;
 }
 
-async function isRoomAliasAvailable(alias) {
+export async function isRoomAliasAvailable(alias) {
   try {
     const result = await initMatrix.matrixClient.resolveRoomAlias(alias);
     if (result.room_id) return false;
@@ -50,7 +50,7 @@ async function isRoomAliasAvailable(alias) {
   }
 }
 
-function getPowerLabel(powerLevel) {
+export function getPowerLabel(powerLevel) {
   if (powerLevel > 9000) return 'Goku';
   if (powerLevel > 100) return 'Founder';
   if (powerLevel === 100) return 'Admin';
@@ -58,7 +58,7 @@ function getPowerLabel(powerLevel) {
   return null;
 }
 
-function parseReply(rawBody) {
+export function parseReply(rawBody) {
   if (rawBody?.indexOf('>') !== 0) return null;
   let body = rawBody.slice(rawBody.indexOf('<') + 1);
   const user = body.slice(0, body.indexOf('>'));
@@ -79,7 +79,7 @@ function parseReply(rawBody) {
   };
 }
 
-function hasDMWith(userId) {
+export function hasDMWith(userId) {
   const mx = initMatrix.matrixClient;
   const directIds = [...initMatrix.roomList.directs];
 
@@ -93,7 +93,7 @@ function hasDMWith(userId) {
   });
 }
 
-function joinRuleToIconSrc(joinRule, isSpace) {
+export function joinRuleToIconSrc(joinRule, isSpace) {
   return ({
     restricted: () => (isSpace ? SpaceIC : HashIC),
     invite: () => (isSpace ? SpaceLockIC : HashLockIC),
@@ -101,8 +101,63 @@ function joinRuleToIconSrc(joinRule, isSpace) {
   }[joinRule]?.() || null);
 }
 
-export {
-  getBaseUrl, getUsername, getUsernameOfRoomMember,
-  isRoomAliasAvailable, getPowerLabel, parseReply,
-  hasDMWith, joinRuleToIconSrc,
-};
+// NOTE: it gives userId with minimum power level 50;
+function getHighestPowerUserId(room) {
+  const userIdToPower = room.currentState.getStateEvents('m.room.power_levels', '')?.getContent().users;
+  let powerUserId = null;
+  if (!userIdToPower) return powerUserId;
+
+  Object.keys(userIdToPower).forEach((userId) => {
+    if (userIdToPower[userId] < 50) return;
+    if (powerUserId === null) {
+      powerUserId = userId;
+      return;
+    }
+    if (userIdToPower[userId] > userIdToPower[powerUserId]) {
+      powerUserId = userId;
+    }
+  });
+  return powerUserId;
+}
+
+export function getIdServer(userId) {
+  const idParts = userId.split(':');
+  return idParts[1];
+}
+
+export function getServerToPopulation(room) {
+  const members = room.getMembers();
+  const serverToPop = {};
+
+  members?.forEach((member) => {
+    const { userId } = member;
+    const server = getIdServer(userId);
+    const serverPop = serverToPop[server];
+    if (serverPop === undefined) {
+      serverToPop[server] = 1;
+      return;
+    }
+    serverToPop[server] = serverPop + 1;
+  });
+
+  return serverToPop;
+}
+
+export function genRoomVia(room) {
+  const via = [];
+  const userId = getHighestPowerUserId(room);
+  if (userId) {
+    const server = getIdServer(userId);
+    if (server) via.push(server);
+  }
+  const serverToPop = getServerToPopulation(room);
+  const sortedServers = Object.keys(serverToPop).sort(
+    (svrA, svrB) => serverToPop[svrB] - serverToPop[svrA],
+  );
+  const mostPop3 = sortedServers.slice(0, 3);
+  if (via.length === 0) return mostPop3;
+  if (mostPop3.includes(via[0])) {
+    mostPop3.splice(mostPop3.indexOf(via[0]), 1);
+  }
+  return via.concat(mostPop3.slice(0, 2));
+}