feat: add the lastJoined and createdAt timestamp from wrapper logic

pull/2620/head
Audric Ackermann 2 years ago
parent 51e4f1dd48
commit b843d66084

@ -206,7 +206,7 @@ const BackButton = (props: { onGoBack: () => void; showBackButton: boolean }) =>
const CallButton = () => { const CallButton = () => {
const isPrivate = useSelectedIsPrivate(); const isPrivate = useSelectedIsPrivate();
const isBlocked = useSelectedIsBlocked(); const isBlocked = useSelectedIsBlocked();
const activeAt = useSelectedIsActive(); const isActive = useSelectedIsActive();
const isMe = useSelectedisNoteToSelf(); const isMe = useSelectedisNoteToSelf();
const selectedConvoKey = useSelectedConversationKey(); const selectedConvoKey = useSelectedConversationKey();
@ -216,7 +216,7 @@ const CallButton = () => {
const isRequest = useIsRequest(selectedConvoKey); const isRequest = useIsRequest(selectedConvoKey);
if (!isPrivate || isMe || !selectedConvoKey || isBlocked || !activeAt || isRequest) { if (!isPrivate || isMe || !selectedConvoKey || isBlocked || !isActive || isRequest) {
return null; return null;
} }

@ -311,6 +311,10 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
if (isPrivate) { if (isPrivate) {
toRet.isPrivate = true; toRet.isPrivate = true;
const foundContact = SessionUtilContact.getContactCached(this.id);
if (!toRet.activeAt && foundContact && isFinite(foundContact.createdAt)) {
toRet.activeAt = foundContact.createdAt;
}
} }
if (weAreAdmin) { if (weAreAdmin) {
@ -342,41 +346,40 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
toRet.currentNotificationSetting = currentNotificationSetting; toRet.currentNotificationSetting = currentNotificationSetting;
} }
const foundContact = SessionUtilContact.getContactCached(this.id); // const foundCommunity = SessionUtilUserGroups.getCommunityByConvoIdCached(this.id);
const foundCommunity = SessionUtilUserGroups.getCommunityByConvoIdCached(this.id); // const foundLegacyGroup = SessionUtilUserGroups.getLegacyGroupCached(this.id);
const foundLegacyGroup = SessionUtilUserGroups.getLegacyGroupCached(this.id); // const foundVolatileInfo = SessionUtilConvoInfoVolatile.getVolatileInfoCached(this.id);
const foundVolatileInfo = SessionUtilConvoInfoVolatile.getVolatileInfoCached(this.id);
// rely on the wrapper values rather than the DB ones if they exist in the wrapper // // rely on the wrapper values rather than the DB ones if they exist in the wrapper
if (foundContact) { // if (foundContact) {
if (foundContact.name) { // if (foundContact.name) {
toRet.displayNameInProfile = foundContact.name; // toRet.displayNameInProfile = foundContact.name;
} // }
if (foundContact.nickname) { // if (foundContact.nickname) {
toRet.nickname = foundContact.nickname; // toRet.nickname = foundContact.nickname;
} // }
if (foundContact.blocked) { // if (foundContact.blocked) {
toRet.isBlocked = foundContact.blocked; // toRet.isBlocked = foundContact.blocked;
} // }
if (foundContact.approvedMe) { // if (foundContact.approvedMe) {
toRet.didApproveMe = foundContact.approvedMe; // toRet.didApproveMe = foundContact.approvedMe;
} // }
if (foundContact.approved) { // if (foundContact.approved) {
toRet.isApproved = foundContact.approved; // toRet.isApproved = foundContact.approved;
} // }
if (foundContact.priority) { // if (foundContact.priority) {
toRet.priority = foundContact.priority; // toRet.priority = foundContact.priority;
} // }
if (foundContact.expirationTimerSeconds > 0) { // if (foundContact.expirationTimerSeconds > 0) {
toRet.expireTimer = foundContact.expirationTimerSeconds; // toRet.expireTimer = foundContact.expirationTimerSeconds;
} // }
} else { // } else {
if (this.get('displayNameInProfile')) { if (this.get('displayNameInProfile')) {
toRet.displayNameInProfile = this.get('displayNameInProfile'); toRet.displayNameInProfile = this.get('displayNameInProfile');
} }
@ -400,22 +403,22 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
if (this.get('expireTimer')) { if (this.get('expireTimer')) {
toRet.expireTimer = this.get('expireTimer'); toRet.expireTimer = this.get('expireTimer');
} }
} // }
// -- Handle the group fields from the wrapper and the database -- // // -- Handle the group fields from the wrapper and the database --
if (foundLegacyGroup) { // if (foundLegacyGroup) {
toRet.members = foundLegacyGroup.members.map(m => m.pubkeyHex) || []; // toRet.members = foundLegacyGroup.members.map(m => m.pubkeyHex) || [];
toRet.groupAdmins = // toRet.groupAdmins =
foundLegacyGroup.members.filter(m => m.isAdmin).map(m => m.pubkeyHex) || []; // foundLegacyGroup.members.filter(m => m.isAdmin).map(m => m.pubkeyHex) || [];
toRet.displayNameInProfile = isEmpty(foundLegacyGroup.name) // toRet.displayNameInProfile = isEmpty(foundLegacyGroup.name)
? undefined // ? undefined
: foundLegacyGroup.name; // : foundLegacyGroup.name;
toRet.expireTimer = foundLegacyGroup.disappearingTimerSeconds; // toRet.expireTimer = foundLegacyGroup.disappearingTimerSeconds;
if (foundLegacyGroup.priority) { // if (foundLegacyGroup.priority) {
toRet.priority = foundLegacyGroup.priority; // toRet.priority = foundLegacyGroup.priority;
} // }
} else if (this.isClosedGroup()) { /*} else*/ if (this.isClosedGroup()) {
toRet.members = this.get('members') || []; toRet.members = this.get('members') || [];
toRet.groupAdmins = this.getGroupAdmins(); toRet.groupAdmins = this.getGroupAdmins();
toRet.displayNameInProfile = this.get('displayNameInProfile'); toRet.displayNameInProfile = this.get('displayNameInProfile');
@ -438,21 +441,21 @@ export class ConversationModel extends Backbone.Model<ConversationAttributes> {
} }
// -- Handle the communities fields from the wrapper and the database -- // -- Handle the communities fields from the wrapper and the database --
if (foundCommunity) { // if (foundCommunity) {
if (foundCommunity.priority) { // if (foundCommunity.priority) {
toRet.priority = foundCommunity.priority; // toRet.priority = foundCommunity.priority;
} // the priorty field is the only one currently in the wrapper community. and we already pre apply the one from the DB on the top of this function // } // the priorty field is the only one currently in the wrapper community. and we already pre apply the one from the DB on the top of this function
} // }
if (foundVolatileInfo) { // if (foundVolatileInfo) {
if (foundVolatileInfo.unread) { // if (foundVolatileInfo.unread) {
toRet.isMarkedUnread = foundVolatileInfo.unread; // toRet.isMarkedUnread = foundVolatileInfo.unread;
} // }
} else { // } else {
if (this.get('markedAsUnread')) { if (this.get('markedAsUnread')) {
toRet.isMarkedUnread = this.get('markedAsUnread'); toRet.isMarkedUnread = this.get('markedAsUnread');
} }
} // }
// -- Handle the field stored only in memory for all types of conversation-- // -- Handle the field stored only in memory for all types of conversation--
const inMemoryConvoInfo = inMemoryConvoInfos.get(this.id); const inMemoryConvoInfo = inMemoryConvoInfos.get(this.id);

@ -1364,13 +1364,21 @@ function insertCommunityIntoWrapper(
function insertLegacyGroupIntoWrapper( function insertLegacyGroupIntoWrapper(
legacyGroup: Pick< legacyGroup: Pick<
ConversationAttributes, ConversationAttributes,
'id' | 'priority' | 'expireTimer' | 'displayNameInProfile' 'id' | 'priority' | 'expireTimer' | 'displayNameInProfile' | 'lastJoinedTimestamp'
> & { members: string; groupAdmins: string }, // members and groupAdmins are still stringified here > & { members: string; groupAdmins: string }, // members and groupAdmins are still stringified here
userGroupConfigWrapper: UserGroupsWrapperInsideWorker, userGroupConfigWrapper: UserGroupsWrapperInsideWorker,
volatileInfoConfigWrapper: ConvoInfoVolatileWrapperInsideWorker, volatileInfoConfigWrapper: ConvoInfoVolatileWrapperInsideWorker,
db: BetterSqlite3.Database db: BetterSqlite3.Database
) { ) {
const { priority, id, expireTimer, groupAdmins, members, displayNameInProfile } = legacyGroup; const {
priority,
id,
expireTimer,
groupAdmins,
members,
displayNameInProfile,
lastJoinedTimestamp,
} = legacyGroup;
const latestEncryptionKeyPairHex = sqlNode.getLatestClosedGroupEncryptionKeyPair( const latestEncryptionKeyPairHex = sqlNode.getLatestClosedGroupEncryptionKeyPair(
legacyGroup.id, legacyGroup.id,
@ -1386,6 +1394,7 @@ function insertLegacyGroupIntoWrapper(
displayNameInProfile, displayNameInProfile,
encPubkeyHex: latestEncryptionKeyPairHex?.publicHex || '', encPubkeyHex: latestEncryptionKeyPairHex?.publicHex || '',
encSeckeyHex: latestEncryptionKeyPairHex?.privateHex || '', encSeckeyHex: latestEncryptionKeyPairHex?.privateHex || '',
lastJoinedTimestamp,
}); });
try { try {

@ -157,7 +157,7 @@ async function handleContactsUpdate(result: IncomingConfResult): Promise<Incomin
} }
if (wrapperConvo.priority !== contactConvo.get('priority')) { if (wrapperConvo.priority !== contactConvo.get('priority')) {
contactConvo.set({ priority: wrapperConvo.priority }); await contactConvo.setPriorityFromWrapper(wrapperConvo.priority);
changes = true; changes = true;
} }
@ -171,8 +171,8 @@ async function handleContactsUpdate(result: IncomingConfResult): Promise<Incomin
changes = true; changes = true;
} }
if (Boolean(wrapperConvo.approvedMe) !== Boolean(contactConvo.didApproveMe())) { if (wrapperConvo.expirationTimerSeconds !== contactConvo.get('expireTimer')) {
await contactConvo.setDidApproveMe(Boolean(wrapperConvo.approvedMe), false); await contactConvo.updateExpireTimer(wrapperConvo.expirationTimerSeconds);
changes = true; changes = true;
} }
@ -382,8 +382,6 @@ async function handleLegacyGroupUpdate(latestEnvelopeTimestamp: number) {
// save the encryption keypair if needed // save the encryption keypair if needed
if (!isEmpty(fromWrapper.encPubkey) && !isEmpty(fromWrapper.encSeckey)) { if (!isEmpty(fromWrapper.encPubkey) && !isEmpty(fromWrapper.encSeckey)) {
try { try {
// TODO we need to store the encryption keypair if needed
const inWrapperKeypair: HexKeyPair = { const inWrapperKeypair: HexKeyPair = {
publicHex: toHex(fromWrapper.encPubkey), publicHex: toHex(fromWrapper.encPubkey),
privateHex: toHex(fromWrapper.encSeckey), privateHex: toHex(fromWrapper.encSeckey),
@ -428,7 +426,10 @@ async function applyConvoVolatileUpdateFromWrapper(
lastReadMessageTimestamp: number lastReadMessageTimestamp: number
) { ) {
const foundConvo = getConversationController().get(convoId); const foundConvo = getConversationController().get(convoId);
if (foundConvo) { if (!foundConvo) {
return;
}
try { try {
window.log.debug( window.log.debug(
`applyConvoVolatileUpdateFromWrapper: ${convoId}: forcedUnread:${forcedUnread}, lastReadMessage:${lastReadMessageTimestamp}` `applyConvoVolatileUpdateFromWrapper: ${convoId}: forcedUnread:${forcedUnread}, lastReadMessage:${lastReadMessageTimestamp}`
@ -452,7 +453,6 @@ async function applyConvoVolatileUpdateFromWrapper(
`applyConvoVolatileUpdateFromWrapper of "${convoId}" failed with error ${e.message}` `applyConvoVolatileUpdateFromWrapper of "${convoId}" failed with error ${e.message}`
); );
} }
}
} }
async function handleConvoInfoVolatileUpdate( async function handleConvoInfoVolatileUpdate(

@ -224,6 +224,7 @@ export async function updateOrCreateClosedGroup(details: GroupInfo) {
> = { > = {
displayNameInProfile: details.name, displayNameInProfile: details.name,
members: details.members, members: details.members,
// Note: legacy group to not support change of admins.
type: ConversationTypeEnum.GROUP, type: ConversationTypeEnum.GROUP,
active_at: details.activeAt ? details.activeAt : 0, active_at: details.activeAt ? details.activeAt : 0,
left: details.activeAt ? false : true, left: details.activeAt ? false : true,

@ -131,6 +131,7 @@ async function insertGroupsFromDBIntoWrapperAndRefresh(convoId: string): Promise
displayNameInProfile: foundConvo.get('displayNameInProfile'), displayNameInProfile: foundConvo.get('displayNameInProfile'),
encPubkeyHex: encryptionKeyPair?.publicHex || '', encPubkeyHex: encryptionKeyPair?.publicHex || '',
encSeckeyHex: encryptionKeyPair?.privateHex || '', encSeckeyHex: encryptionKeyPair?.privateHex || '',
lastJoinedTimestamp: foundConvo.get('lastJoinedTimestamp') || 0,
}); });
try { try {

@ -239,7 +239,7 @@ export const _getConversationComparator = (testingi18n?: LocalizerType) => {
if (rightPriority > leftPriority) { if (rightPriority > leftPriority) {
return 1; return 1;
} }
// Then if none is pinned, check other criteria // Then if none are pinned, check other criteria
const leftActiveAt = left.activeAt; const leftActiveAt = left.activeAt;
const rightActiveAt = right.activeAt; const rightActiveAt = right.activeAt;
if (leftActiveAt && !rightActiveAt) { if (leftActiveAt && !rightActiveAt) {
@ -262,7 +262,7 @@ export const getConversationComparator = createSelector(getIntl, _getConversatio
// export only because we use it in some of our tests // export only because we use it in some of our tests
// tslint:disable-next-line: cyclomatic-complexity // tslint:disable-next-line: cyclomatic-complexity
export const _getLeftPaneLists = ( const _getLeftPaneLists = (
sortedConversations: Array<ReduxConversationType> sortedConversations: Array<ReduxConversationType>
): { ): {
conversations: Array<ReduxConversationType>; conversations: Array<ReduxConversationType>;
@ -401,13 +401,13 @@ const _getPrivateContactsPubkeys = (
sortedConversations: Array<ReduxConversationType> sortedConversations: Array<ReduxConversationType>
): Array<string> => { ): Array<string> => {
return filter(sortedConversations, conversation => { return filter(sortedConversations, conversation => {
return ( return !!(
conversation.isPrivate && conversation.isPrivate &&
!conversation.isBlocked && !conversation.isBlocked &&
!conversation.isMe && !conversation.isMe &&
conversation.didApproveMe && conversation.didApproveMe &&
conversation.isApproved && conversation.isApproved &&
Boolean(conversation.activeAt) conversation.activeAt
); );
}).map(convo => convo.id); }).map(convo => convo.id);
}; };
@ -450,8 +450,9 @@ export type DirectContactsByNameType = {
export const getDirectContactsByName = createSelector( export const getDirectContactsByName = createSelector(
getDirectContacts, getDirectContacts,
(contacts: Array<ReduxConversationType>): Array<DirectContactsByNameType> => { (contacts: Array<ReduxConversationType>): Array<DirectContactsByNameType> => {
const us = UserUtils.getOurPubKeyStrFromCache();
const extractedContacts = contacts const extractedContacts = contacts
.filter(m => m.id !== UserUtils.getOurPubKeyStrFromCache()) .filter(m => m.id !== us)
.map(m => { .map(m => {
return { return {
id: m.id, id: m.id,

@ -145,6 +145,7 @@ export function getContactInfoFromDBValues({
!!expirationTimerSeconds && isFinite(expirationTimerSeconds) && expirationTimerSeconds > 0 !!expirationTimerSeconds && isFinite(expirationTimerSeconds) && expirationTimerSeconds > 0
? 'disappearAfterSend' ? 'disappearAfterSend'
: 'off', : 'off',
createdAt: 0, // this is actually unused as the wrapper keep the value as it is currently stored (this is a created at timestamp, no need to update it)
}; };
if ( if (
@ -204,7 +205,11 @@ export function getLegacyGroupInfoFromDBValues({
encPubkeyHex, encPubkeyHex,
encSeckeyHex, encSeckeyHex,
groupAdmins: maybeAdmins, groupAdmins: maybeAdmins,
}: Pick<ConversationAttributes, 'id' | 'priority' | 'displayNameInProfile' | 'expireTimer'> & { lastJoinedTimestamp,
}: Pick<
ConversationAttributes,
'id' | 'priority' | 'displayNameInProfile' | 'expireTimer' | 'lastJoinedTimestamp'
> & {
encPubkeyHex: string; encPubkeyHex: string;
encSeckeyHex: string; encSeckeyHex: string;
members: string | Array<string>; members: string | Array<string>;
@ -227,6 +232,7 @@ export function getLegacyGroupInfoFromDBValues({
members: wrappedMembers, members: wrappedMembers,
encPubkey: !isEmpty(encPubkeyHex) ? from_hex(encPubkeyHex) : new Uint8Array(), encPubkey: !isEmpty(encPubkeyHex) ? from_hex(encPubkeyHex) : new Uint8Array(),
encSeckey: !isEmpty(encSeckeyHex) ? from_hex(encSeckeyHex) : new Uint8Array(), encSeckey: !isEmpty(encSeckeyHex) ? from_hex(encSeckeyHex) : new Uint8Array(),
joinedAt: lastJoinedTimestamp,
}; };
return legacyGroup; return legacyGroup;

Loading…
Cancel
Save