Skip to content

Commit

Permalink
Merge pull request #788 from ephemeraHQ/saulmc/persist-group-creator-…
Browse files Browse the repository at this point in the history
…addedby

persist data for inbox filtering right away
  • Loading branch information
saulmc authored Sep 20, 2024
2 parents 22b3985 + ab557e3 commit 44b2561
Show file tree
Hide file tree
Showing 15 changed files with 131 additions and 40 deletions.
2 changes: 2 additions & 0 deletions data/db/datasource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ import { AddIndexToSent1712656017130 } from "./migrations/1712656017130-addIndex
import { RemoveSentViaConverse1717625558678 } from "./migrations/1717625558678-RemoveSentViaConverse";
import { AddSuperAdmin1717631723249 } from "./migrations/1717631723249-AddSuperAdmin";
import { AddIsActive1721143963530 } from "./migrations/1721143963530-addIsActive";
import { AddGroupCreatorAndAddedBy1726807503232 } from "./migrations/1726807503232-AddGroupCreatorAndAddedBy";
import { RemoveProfile1726828413530 } from "./migrations/1726828413530-removeProfileDb";

// We now use built in SQLite v3.45.1 from op-sqlite
Expand Down Expand Up @@ -99,6 +100,7 @@ export const getDataSource = async (account: string) => {
RemoveSentViaConverse1717625558678,
AddSuperAdmin1717631723249,
AddIsActive1721143963530,
AddGroupCreatorAndAddedBy1726807503232,
RemoveProfile1726828413530,
],
type: "react-native",
Expand Down
6 changes: 6 additions & 0 deletions data/db/entities/conversationEntity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,12 @@ export class Conversation {
@Column("simple-array", { nullable: true })
groupMembers?: string[];

@Column("text", { nullable: true })
groupCreator?: string;

@Column("text", { nullable: true })
groupAddedBy?: string;

@Column("boolean", { nullable: true })
isActive?: boolean;

Expand Down
49 changes: 49 additions & 0 deletions data/db/migrations/1726807503232-AddGroupCreatorAndAddedBy.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { MigrationInterface, QueryRunner } from "typeorm";

export class AddGroupCreatorAndAddedBy1726807503232
implements MigrationInterface
{
name = "AddGroupCreatorAndAddedBy1726807503232";

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP INDEX "IDX_b895a35679cdf0702fb2218718"`);
await queryRunner.query(`DROP INDEX "IDX_134e668e0d62c7cd93624ea4d5"`);
await queryRunner.query(
`CREATE TABLE "temporary_conversation" ("topic" text PRIMARY KEY NOT NULL, "peerAddress" text, "createdAt" integer NOT NULL, "contextConversationId" text, "contextMetadata" text, "readUntil" integer NOT NULL DEFAULT (0), "pending" boolean NOT NULL DEFAULT (0), "version" text NOT NULL DEFAULT ('v2'), "spamScore" decimal(6,2), "isGroup" boolean NOT NULL DEFAULT (0), "groupMembers" text, "groupAdmins" text, "groupPermissionLevel" text, "lastNotificationsSubscribedPeriod" integer, "groupSuperAdmins" text, "groupName" text, "isActive" boolean, "groupCreator" text, "groupAddedBy" text)`
);
await queryRunner.query(
`INSERT INTO "temporary_conversation"("topic", "peerAddress", "createdAt", "contextConversationId", "contextMetadata", "readUntil", "pending", "version", "spamScore", "isGroup", "groupMembers", "groupAdmins", "groupPermissionLevel", "lastNotificationsSubscribedPeriod", "groupSuperAdmins", "groupName", "isActive") SELECT "topic", "peerAddress", "createdAt", "contextConversationId", "contextMetadata", "readUntil", "pending", "version", "spamScore", "isGroup", "groupMembers", "groupAdmins", "groupPermissionLevel", "lastNotificationsSubscribedPeriod", "groupSuperAdmins", "groupName", "isActive" FROM "conversation"`
);
await queryRunner.query(`DROP TABLE "conversation"`);
await queryRunner.query(
`ALTER TABLE "temporary_conversation" RENAME TO "conversation"`
);
await queryRunner.query(
`CREATE INDEX "IDX_b895a35679cdf0702fb2218718" ON "conversation" ("peerAddress") `
);
await queryRunner.query(
`CREATE INDEX "IDX_134e668e0d62c7cd93624ea4d5" ON "conversation" ("pending") `
);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(`DROP INDEX "IDX_134e668e0d62c7cd93624ea4d5"`);
await queryRunner.query(`DROP INDEX "IDX_b895a35679cdf0702fb2218718"`);
await queryRunner.query(
`ALTER TABLE "conversation" RENAME TO "temporary_conversation"`
);
await queryRunner.query(
`CREATE TABLE "conversation" ("topic" text PRIMARY KEY NOT NULL, "peerAddress" text, "createdAt" integer NOT NULL, "contextConversationId" text, "contextMetadata" text, "readUntil" integer NOT NULL DEFAULT (0), "pending" boolean NOT NULL DEFAULT (0), "version" text NOT NULL DEFAULT ('v2'), "spamScore" decimal(6,2), "isGroup" boolean NOT NULL DEFAULT (0), "groupMembers" text, "groupAdmins" text, "groupPermissionLevel" text, "lastNotificationsSubscribedPeriod" integer, "groupSuperAdmins" text, "groupName" text, "isActive" boolean)`
);
await queryRunner.query(
`INSERT INTO "conversation"("topic", "peerAddress", "createdAt", "contextConversationId", "contextMetadata", "readUntil", "pending", "version", "spamScore", "isGroup", "groupMembers", "groupAdmins", "groupPermissionLevel", "lastNotificationsSubscribedPeriod", "groupSuperAdmins", "groupName", "isActive") SELECT "topic", "peerAddress", "createdAt", "contextConversationId", "contextMetadata", "readUntil", "pending", "version", "spamScore", "isGroup", "groupMembers", "groupAdmins", "groupPermissionLevel", "lastNotificationsSubscribedPeriod", "groupSuperAdmins", "groupName", "isActive" FROM "temporary_conversation"`
);
await queryRunner.query(`DROP TABLE "temporary_conversation"`);
await queryRunner.query(
`CREATE INDEX "IDX_134e668e0d62c7cd93624ea4d5" ON "conversation" ("pending") `
);
await queryRunner.query(
`CREATE INDEX "IDX_b895a35679cdf0702fb2218718" ON "conversation" ("peerAddress") `
);
}
}
30 changes: 18 additions & 12 deletions data/helpers/conversations/spamScore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,8 @@ export const saveSpamScores = async (
export const refreshAllSpamScores = async (account: string) => {
const { conversations } = getChatStore(account).getState();
const conversationsToScore = Object.values(conversations).filter(
(c) =>
c.messagesIds.length &&
(c.spamScore === undefined || c.spamScore === null)
(c) => c.spamScore === undefined || c.spamScore === null
);

if (conversationsToScore.length === 0) return;
await computeConversationsSpamScores(account, conversationsToScore);
};
Expand All @@ -61,21 +58,30 @@ export const computeConversationsSpamScores = async (
account: string,
conversations: XmtpConversationWithUpdate[]
) => {
// @todo => spam score for group convos??
const conversationsPeerAddresses = new Set(
const conversationsRequesterAddresses = new Set(
conversations
.filter((c) => !!c.peerAddress)
.map((c) => c.peerAddress as string)
.filter((c) => !!c.peerAddress || !!c.groupAddedBy)
.map((c) => (c.isGroup ? c.groupAddedBy : (c.peerAddress as string)))
.filter((address): address is string => address !== undefined)
);
const sendersSpamScores = await getSendersSpamScores(
Array.from(conversationsPeerAddresses)
Array.from(conversationsRequesterAddresses)
);
const topicSpamScores: TopicSpamScores = {};

conversations.forEach((conversation) => {
if (!conversation.peerAddress) return;
const senderSpamScore = sendersSpamScores[conversation.peerAddress];
if (!conversation.messagesIds.length && senderSpamScore) {
if (!(conversation.peerAddress || conversation.groupAddedBy)) return;

const senderKey = conversation.isGroup
? conversation.groupAddedBy
: conversation.peerAddress;
if (!senderKey) return;

const senderSpamScore = sendersSpamScores[senderKey];
if (
!conversation.messagesIds.length &&
typeof senderSpamScore === "number"
) {
// Cannot score an empty conversation further, score is just the
// sender spam score
topicSpamScores[conversation.topic] = senderSpamScore;
Expand Down
17 changes: 16 additions & 1 deletion data/helpers/conversations/upsertConversations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import logger from "@utils/logger";
import { In } from "typeorm/browser";

import { upgradePendingConversationsIfNeeded } from "./pendingConversations";
import { computeConversationsSpamScores } from "./spamScore";
import {
navigateToTopicWithRetry,
topicToNavigateTo,
Expand All @@ -12,7 +13,10 @@ import { Conversation } from "../../db/entities/conversationEntity";
import { upsertRepository } from "../../db/upsert";
import { xmtpConversationToDb } from "../../mappers";
import { getChatStore } from "../../store/accountsStore";
import { XmtpConversation } from "../../store/chatStore";
import {
XmtpConversation,
XmtpConversationWithUpdate,
} from "../../store/chatStore";
import { refreshProfilesIfNeeded } from "../profiles/profilesUpdate";

export const saveConversations = async (
Expand Down Expand Up @@ -79,6 +83,17 @@ const setupAndSaveConversations = async (
const alreadyConversationInDbWithTopic =
alreadyConversationsByTopic[conversation.topic];

// If spam score is not computed, compute it
if (
conversation.spamScore === undefined ||
conversation.spamScore === null
) {
logger.debug("Empty spam score, computing...");
computeConversationsSpamScores(account, [
conversation as XmtpConversationWithUpdate,
]);
}

conversation.readUntil =
conversation.readUntil ||
alreadyConversationInDbWithTopic?.readUntil ||
Expand Down
4 changes: 4 additions & 0 deletions data/mappers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,8 @@ export const xmtpConversationToDb = (
isGroup: xmtpConversation.isGroup,
isActive: xmtpConversation.isGroup ? !!xmtpConversation.isActive : true,
groupMembers: xmtpConversation.groupMembers,
groupCreator: xmtpConversation.groupCreator,
groupAddedBy: xmtpConversation.groupAddedBy,
groupName: xmtpConversation.isGroup ? xmtpConversation.groupName : undefined,
groupPermissionLevel: xmtpConversation.groupPermissionLevel,
lastNotificationsSubscribedPeriod:
Expand Down Expand Up @@ -131,6 +133,8 @@ export const xmtpConversationFromDb = (
isGroup: dbConversation.isGroup,
isActive: dbConversation.isGroup ? !!dbConversation.isActive : true,
groupMembers,
groupCreator: dbConversation.groupCreator,
groupAddedBy: dbConversation.groupAddedBy,
groupAdmins: dbConversation.groupAdmins,
groupName: dbConversation.groupName,
groupPermissionLevel: dbConversation.groupPermissionLevel,
Expand Down
2 changes: 2 additions & 0 deletions data/store/chatStore.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ export type XmtpDMConversation = XmtpConversationShared & {
groupMembers?: undefined;
groupAdmins?: undefined;
groupPermissionLevel?: undefined;
groupCreator?: undefined;
groupAddedBy?: undefined;
};

export type XmtpGroupConversation = XmtpConversationShared & {
Expand Down
2 changes: 2 additions & 0 deletions i18n/translations/en.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ const en = {
hidden_requests: "Hidden requests",
suggestion_text:
"Based on your onchain history, we've made some suggestions on who you may know.",
no_suggestions_text:
"You currently have no message requests. We'll make suggestions here as you connect with others.",
hidden_requests_warn:
"Requests containing messages that may be offensive or unwanted are moved to this folder.",

Expand Down
2 changes: 1 addition & 1 deletion ios/Podfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2418,7 +2418,7 @@ SPEC CHECKSUMS:
web3.swift: 2263d1e12e121b2c42ffb63a5a7beb1acaf33959
XMTP: a9e7382ec5b57eeda3df7b177f034d061e3c9b61
XMTPReactNative: 63c46d6ba9b8dc5831ea49e8716f4b60cc012651
Yoga: 1ab23c1835475da69cf14e211a560e73aab24cb0
Yoga: 33622183a85805e12703cd618b2c16bfd18bfffb

PODFILE CHECKSUM: beb6a8b55061fc0f811288dc66c75239474eba01

Expand Down
43 changes: 18 additions & 25 deletions screens/Navigation/ConversationRequestsListNav.ios.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -132,51 +132,44 @@ export default function ConversationRequestsListNav() {

const hasLikelyNotSpam = likelyNotSpam.length > 0;
const hasSpam = likelySpam.length > 0;
const hasBothTypesOfRequests = hasLikelyNotSpam && hasSpam;
const hasBothTypesOfRequests = true;

const handleSegmentChange = (index: number) => {
setSelectedSegment(index);
};

const renderSegmentedController = () => {
if (hasBothTypesOfRequests) {
return (
<RequestsSegmentedController
options={[translate("you_might_know"), translate("hidden_requests")]}
selectedIndex={selectedSegment}
onSelect={handleSegmentChange}
/>
);
}
return null;
return (
<RequestsSegmentedController
options={[translate("you_might_know"), translate("hidden_requests")]}
selectedIndex={selectedSegment}
onSelect={handleSegmentChange}
/>
);
};

const renderContent = (navigationProps: {
route: RouteProp<NavigationParamList, "ChatsRequests">;
navigation: NativeStackNavigationProp<NavigationParamList, "ChatsRequests">;
}) => {
const showSuggestionText =
(hasBothTypesOfRequests && selectedSegment === 0) ||
(!hasBothTypesOfRequests && hasLikelyNotSpam);
const showSpamWarning =
(hasBothTypesOfRequests && selectedSegment === 1) ||
(!hasBothTypesOfRequests && hasSpam);
const itemsToShow = hasBothTypesOfRequests
? selectedSegment === 0
? likelyNotSpam
: likelySpam
: hasLikelyNotSpam
? likelyNotSpam
: likelySpam;
const showSuggestionText = selectedSegment === 0 && hasLikelyNotSpam;
const showNoSuggestionsText = selectedSegment === 0 && !hasLikelyNotSpam;
const showSpamWarning = selectedSegment === 1;
const itemsToShow = selectedSegment === 0 ? likelyNotSpam : likelySpam;

return (
<>
{hasBothTypesOfRequests && renderSegmentedController()}
{renderSegmentedController()}
{showSuggestionText && (
<Text style={styles.suggestionText}>
{translate("suggestion_text")}
</Text>
)}
{showNoSuggestionsText && (
<Text style={styles.suggestionText}>
{translate("no_suggestions_text")}
</Text>
)}
{showSpamWarning && (
<Text style={styles.suggestionText}>
{translate("hidden_requests_warn")}
Expand Down
Binary file modified scripts/migrations/converse-sample.sqlite
Binary file not shown.
2 changes: 2 additions & 0 deletions scripts/migrations/datasource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import { AddIndexToSent1712656017130 } from "../../data/db/migrations/1712656017
import { RemoveSentViaConverse1717625558678 } from "../../data/db/migrations/1717625558678-RemoveSentViaConverse";
import { AddSuperAdmin1717631723249 } from "../../data/db/migrations/1717631723249-AddSuperAdmin";
import { AddIsActive1721143963530 } from "../../data/db/migrations/1721143963530-addIsActive";
import { AddGroupCreatorAndAddedBy1726807503232 } from "../../data/db/migrations/1726807503232-AddGroupCreatorAndAddedBy";
import { RemoveProfile1726828413530 } from "../../data/db/migrations/1726828413530-removeProfileDb";

const dataSource = new DataSource({
Expand Down Expand Up @@ -67,6 +68,7 @@ const dataSource = new DataSource({
RemoveSentViaConverse1717625558678,
AddSuperAdmin1717631723249,
AddIsActive1721143963530,
AddGroupCreatorAndAddedBy1726807503232,
RemoveProfile1726828413530,
],
type: "sqlite",
Expand Down
2 changes: 2 additions & 0 deletions scripts/migrations/db.ts
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,8 @@ const commands = {
groupMembers: [peerAddress, myAddress],
groupAdmins: [myAddress],
groupSuperAdmins: [myAddress],
groupCreator: myAddress,
groupAddedBy: myAddress,
});

for (let messageIndex = 0; messageIndex < 10; messageIndex++) {
Expand Down
6 changes: 6 additions & 0 deletions scripts/migrations/entities/conversationEntity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ export class Conversation {
@Column("simple-array", { nullable: true })
groupMembers?: string[];

@Column("text", { nullable: true })
groupCreator?: string;

@Column("text", { nullable: true })
groupAddedBy?: string;

@Column("boolean", { nullable: true })
isActive?: boolean;

Expand Down
4 changes: 3 additions & 1 deletion utils/xmtpRN/conversations.ts
Original file line number Diff line number Diff line change
Expand Up @@ -804,7 +804,9 @@ export const sortRequestsBySpamScore = (
requests.forEach((conversation) => {
const isLikelyNotSpam =
conversation.spamScore !== undefined &&
(conversation.spamScore === null || conversation.spamScore < 1);
(conversation.spamScore === null || conversation.spamScore < 1) &&
conversation.version !== ConversationVersion.GROUP;
// @todo => remove this once we have group-specific spam scores

if (isLikelyNotSpam) {
result.likelyNotSpam.push(conversation);
Expand Down

0 comments on commit 44b2561

Please sign in to comment.