Skip to content

Commit b7a6862

Browse files
committed
feat: add timestamp to track when a profile was updated
so we can always show the correct one
1 parent 90f64ef commit b7a6862

File tree

15 files changed

+138
-10
lines changed

15 files changed

+138
-10
lines changed

include/contacts_config.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ class ContactsConfigWrapper : public ConfigBaseImpl,
2020
Napi::Value get(const Napi::CallbackInfo& info);
2121
Napi::Value getAll(const Napi::CallbackInfo& info);
2222
void set(const Napi::CallbackInfo& info);
23+
Napi::Value setProfileUpdatedSeconds(const Napi::CallbackInfo& info);
2324
Napi::Value erase(const Napi::CallbackInfo& info);
2425
};
2526

include/groups/meta_group_wrapper.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ class MetaGroupWrapper : public Napi::ObjectWrap<MetaGroupWrapper> {
7272
void memberSetPromotionFailed(const Napi::CallbackInfo& info);
7373
void memberSetPromotionAccepted(const Napi::CallbackInfo& info);
7474
void memberSetProfilePicture(const Napi::CallbackInfo& info);
75+
void memberSetProfileUpdatedSeconds(const Napi::CallbackInfo& info);
7576
Napi::Value memberResetAllSendingState(const Napi::CallbackInfo& info);
7677
void memberSetSupplement(const Napi::CallbackInfo& info);
7778
Napi::Value memberEraseAndRekey(const Napi::CallbackInfo& info);

include/user_config.hpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,9 @@ class UserConfigWrapper : public ConfigBaseImpl, public Napi::ObjectWrap<UserCon
2323
void setPriority(const Napi::CallbackInfo& info);
2424
void setName(const Napi::CallbackInfo& info);
2525
void setNameTruncated(const Napi::CallbackInfo& info);
26-
void setProfilePic(const Napi::CallbackInfo& info);
26+
void setNewProfilePic(const Napi::CallbackInfo& info);
27+
void setReuploadProfilePic(const Napi::CallbackInfo& info);
28+
Napi::Value getProfileUpdatedSeconds(const Napi::CallbackInfo& info);
2729

2830
Napi::Value getEnableBlindedMsgRequest(const Napi::CallbackInfo& info);
2931
void setEnableBlindedMsgRequest(const Napi::CallbackInfo& info);

include/utilities.hpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ std::vector<unsigned char> toCppBuffer(Napi::Value x, const std::string& identif
5959
int64_t toCppInteger(Napi::Value x, const std::string& identifier, bool allowUndefined = false);
6060
std::optional<int64_t> maybeNonemptyInt(Napi::Value x, const std::string& identifier);
6161
std::optional<bool> maybeNonemptyBoolean(Napi::Value x, const std::string& identifier);
62+
std::optional<std::chrono::sys_seconds> maybeNonemptySysSeconds(
63+
Napi::Value x, const std::string& identifier);
6264

6365
bool toCppBoolean(Napi::Value x, const std::string& identifier);
6466

@@ -109,6 +111,13 @@ struct toJs_impl<session::config::Namespace> {
109111
}
110112
};
111113

114+
template <>
115+
struct toJs_impl<std::chrono::sys_seconds> {
116+
auto operator()(const Napi::Env& env, std::chrono::sys_seconds t) const {
117+
return Napi::Number::New(env, t.time_since_epoch().count());
118+
}
119+
};
120+
112121
template <typename T>
113122
struct toJs_impl<T, std::enable_if_t<std::is_arithmetic_v<T>>> {
114123
auto operator()(const Napi::Env& env, T n) const { return Napi::Number::New(env, n); }

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"main": "index.js",
33
"name": "libsession_util_nodejs",
44
"description": "Wrappers for the Session Util Library",
5-
"version": "0.5.5",
5+
"version": "0.5.6",
66
"license": "GPL-3.0",
77
"author": {
88
"name": "Oxen Project",

src/contacts_config.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ struct toJs_impl<contact_info> {
4444
obj["nickname"] = toJs(env, maybe_string(contact.nickname));
4545
obj["approved"] = toJs(env, contact.approved);
4646
obj["approvedMe"] = toJs(env, contact.approved_me);
47+
obj["profileUpdatedSeconds"] = toJs(env, contact.profile_updated);
4748
obj["blocked"] = toJs(env, contact.blocked);
4849
obj["priority"] = toJs(env, contact.priority);
4950
obj["createdAtSeconds"] = toJs(env, contact.created);
@@ -64,7 +65,11 @@ void ContactsConfigWrapper::Init(Napi::Env env, Napi::Object exports) {
6465
InstanceMethod("get", &ContactsConfigWrapper::get),
6566
InstanceMethod("getAll", &ContactsConfigWrapper::getAll),
6667
InstanceMethod("set", &ContactsConfigWrapper::set),
68+
InstanceMethod(
69+
"setProfileUpdatedSeconds",
70+
&ContactsConfigWrapper::setProfileUpdatedSeconds),
6771
InstanceMethod("erase", &ContactsConfigWrapper::erase),
72+
6873
});
6974
}
7075

@@ -150,6 +155,32 @@ void ContactsConfigWrapper::set(const Napi::CallbackInfo& info) {
150155
});
151156
}
152157

158+
Napi::Value ContactsConfigWrapper::setProfileUpdatedSeconds(const Napi::CallbackInfo& info) {
159+
return wrapResult(info, [&] {
160+
assertInfoLength(info, 1);
161+
162+
auto arg = info[0];
163+
assertIsObject(arg);
164+
auto obj = arg.As<Napi::Object>();
165+
166+
if (obj.IsEmpty())
167+
throw std::invalid_argument("setProfileUpdatedSeconds received empty");
168+
169+
auto sessionID = toCppString(obj.Get("id"), "contacts.setProfileUpdatedSeconds, id");
170+
auto contact = config.get(sessionID);
171+
172+
auto seconds = maybeNonemptySysSeconds(
173+
obj.Get("profileUpdatedSeconds"),
174+
"contacts.setProfileUpdatedSeconds, profileUpdatedSeconds");
175+
if (contact && seconds) {
176+
config.set_profile_updated(sessionID, seconds.value());
177+
config.set(*contact);
178+
return true;
179+
}
180+
return false;
181+
});
182+
}
183+
153184
/** ==============================
154185
* ERASERS
155186
* ============================== */

src/groups/meta_group_wrapper.cpp

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ Napi::Object member_to_js(const Napi::Env& env, const member& info, const member
1717
obj["pubkeyHex"] = toJs(env, info.session_id);
1818
obj["name"] = toJs(env, info.name);
1919
obj["profilePicture"] = toJs(env, info.profile_picture);
20+
obj["profileUpdatedSeconds"] = toJs(env, info.profile_updated);
2021
obj["supplement"] = toJs(env, info.supplement);
2122

2223
switch (status) {
@@ -131,6 +132,9 @@ void MetaGroupWrapper::Init(Napi::Env env, Napi::Object exports) {
131132
&MetaGroupWrapper::memberSetPromotionAccepted),
132133
InstanceMethod(
133134
"memberSetProfilePicture", &MetaGroupWrapper::memberSetProfilePicture),
135+
InstanceMethod(
136+
"memberSetProfileUpdatedSeconds",
137+
&MetaGroupWrapper::memberSetProfileUpdatedSeconds),
134138
InstanceMethod(
135139
"memberResetAllSendingState",
136140
&MetaGroupWrapper::memberResetAllSendingState),
@@ -669,6 +673,23 @@ void MetaGroupWrapper::memberSetProfilePicture(const Napi::CallbackInfo& info) {
669673
});
670674
}
671675

676+
void MetaGroupWrapper::memberSetProfileUpdatedSeconds(const Napi::CallbackInfo& info) {
677+
wrapExceptions(info, [&] {
678+
assertInfoLength(info, 2);
679+
assertIsString(info[0]);
680+
assertIsObject(info[1]);
681+
682+
auto pubkeyHex = toCppString(info[0], "memberSetProfiUpdatedSeconds");
683+
auto updatedAtSeconds = maybeNonemptySysSeconds(info[1], "memberSetProfiUpdatedSeconds");
684+
685+
auto m = this->meta_group->members->get(pubkeyHex);
686+
if (m) {
687+
m->profile_updated = updatedAtSeconds.value();
688+
this->meta_group->members->set(*m);
689+
}
690+
});
691+
}
692+
672693
Napi::Value MetaGroupWrapper::memberResetAllSendingState(const Napi::CallbackInfo& info) {
673694
return wrapResult(info, [&] {
674695
bool changed = false;

src/user_config.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,15 @@ void UserConfigWrapper::Init(Napi::Env env, Napi::Object exports) {
2020
InstanceMethod("getPriority", &UserConfigWrapper::getPriority),
2121
InstanceMethod("getName", &UserConfigWrapper::getName),
2222
InstanceMethod("getProfilePic", &UserConfigWrapper::getProfilePic),
23+
InstanceMethod(
24+
"getProfileUpdatedSeconds",
25+
&UserConfigWrapper::getProfileUpdatedSeconds),
26+
InstanceMethod(
27+
"setReuploadProfilePic", &UserConfigWrapper::setReuploadProfilePic),
2328
InstanceMethod("setPriority", &UserConfigWrapper::setPriority),
2429
InstanceMethod("setName", &UserConfigWrapper::setName),
2530
InstanceMethod("setNameTruncated", &UserConfigWrapper::setNameTruncated),
26-
InstanceMethod("setProfilePic", &UserConfigWrapper::setProfilePic),
31+
InstanceMethod("setNewProfilePic", &UserConfigWrapper::setNewProfilePic),
2732
InstanceMethod(
2833
"getEnableBlindedMsgRequest",
2934
&UserConfigWrapper::getEnableBlindedMsgRequest),
@@ -107,7 +112,7 @@ void UserConfigWrapper::setNameTruncated(const Napi::CallbackInfo& info) {
107112
});
108113
}
109114

110-
void UserConfigWrapper::setProfilePic(const Napi::CallbackInfo& info) {
115+
void UserConfigWrapper::setNewProfilePic(const Napi::CallbackInfo& info) {
111116
return wrapExceptions(info, [&] {
112117
assertInfoLength(info, 1);
113118
auto profile_pic_obj = info[0];
@@ -119,6 +124,23 @@ void UserConfigWrapper::setProfilePic(const Napi::CallbackInfo& info) {
119124
});
120125
}
121126

127+
void UserConfigWrapper::setReuploadProfilePic(const Napi::CallbackInfo& info) {
128+
assertInfoLength(info, 1);
129+
auto profile_pic_obj = info[0];
130+
131+
if (!profile_pic_obj.IsNull() && !profile_pic_obj.IsUndefined())
132+
assertIsObject(profile_pic_obj);
133+
134+
config.set_reupload_profile_pic(profile_pic_from_object(profile_pic_obj));
135+
}
136+
137+
Napi::Value UserConfigWrapper::getProfileUpdatedSeconds(const Napi::CallbackInfo& info) {
138+
return wrapResult(info, [&] {
139+
auto env = info.Env();
140+
return config.get_profile_updated();
141+
});
142+
}
143+
122144
Napi::Value UserConfigWrapper::getEnableBlindedMsgRequest(const Napi::CallbackInfo& info) {
123145
return wrapResult(info, [&] {
124146
auto env = info.Env();

src/utilities.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,18 @@ std::optional<int64_t> maybeNonemptyInt(Napi::Value x, const std::string& identi
138138
throw std::invalid_argument{"maybeNonemptyInt with invalid type, called from " + identifier};
139139
}
140140

141+
std::optional<std::chrono::sys_seconds> maybeNonemptySysSeconds(Napi::Value x, const std::string& identifier) {
142+
if (x.IsNull() || x.IsUndefined())
143+
return std::nullopt;
144+
145+
if (x.IsNumber()) {
146+
auto num = x.As<Napi::Number>().Int64Value();
147+
return std::chrono::sys_seconds{std::chrono::seconds{num}};
148+
}
149+
150+
throw std::invalid_argument{"maybeNonemptyTime with invalid type, called from " + identifier};
151+
}
152+
141153
std::optional<bool> maybeNonemptyBoolean(Napi::Value x, const std::string& identifier) {
142154
if (x.IsNull() || x.IsUndefined())
143155
return std::nullopt;

0 commit comments

Comments
 (0)